百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

duilib 窗口创建流程梳理 duilib界面开发

liebian365 2024-10-30 04:50 23 浏览 0 评论


1 duilib窗口类

<Window size="400,150" caption="0,0,0,60" roundcorner="16,16" shadowattached="false">

duilib自己封装了Window类

class UILIB_API Window : public virtual nbase::SupportWeakCallback
{
public:
    Window();
	~Window();

	/**
	 * @brief 获取窗口所属的 Windows 句柄
	 * @return 返回窗口关联的 Windows 窗口句柄
	 */
    HWND GetHWND() const;

	/**
	 * @brief 注册窗口类
	 * @return 返回 true 表示成功,否则表示失败
	 */
    bool RegisterWindowClass();

	/**
	 * @brief 注册控件窗口类(与窗口的过程函数不同)
	 * @return 返回 true 表示成功,否则表示失败
	 */
    bool RegisterSuperClass();

	/**
	 * @brief 获取窗口类名称
	 * @return 返回窗口类名称
	 */
	virtual std::wstring GetWindowClassName() const;

	/**
	 * @brief 获取控件窗口类
	 * @return 返回控件窗口类
	 */
	virtual std::wstring GetSuperClassName() const;

	/**
	 * @brief 获取窗口类的样式,该方法由实例化的子类实现,https://docs.microsoft.com/en-us/windows/desktop/winmsg/window-class-styles
	 * @return 返回窗口类的样式
	 */
	virtual UINT GetClassStyle() const;

	/**
	 * @brief 子类化窗口(更改窗口过程函数)
	 * @param[in] 窗口句柄
	 * @return 新的窗口句柄
	 */
	HWND Subclass(HWND hWnd);

	/**
	 * @brief 取消子类化窗口(恢复原来的窗口过程函数)
	 * @return 无
	 */
	void Unsubclass();

	/**
	 * @brief 创建窗口
	 * @param[in] hwndParent 父窗口句柄
	 * @param[in] pstrName 窗口名称
	 * @param[in] dwStyle 窗口样式
	 * @param[in] dwExStyle 窗口拓展样式
	 * @param[in] isLayeredWindow 是否带有层窗口属性,默认为 true
	 * @param[in] rc 窗口大小
	 * @return 返回窗口句柄
	 */
	virtual HWND Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, bool isLayeredWindow = true, const UiRect& rc = UiRect(0, 0, 0, 0));

	/**
	 * @brief 关闭窗口
	 * @param[in] 关闭消息
	 * @return 无
	 */
	virtual void Close(UINT nRet = IDOK);




其中,创建窗口使用

* @brief 创建窗口 * @param[in] hwndParent 父窗口句柄 * @param[in] pstrName 窗口名称 * @param[in] dwStyle 窗口样式 * @param[in] dwExStyle 窗口拓展样式 * @param[in] isLayeredWindow 是否带有层窗口属性,默认为 true * @param[in] rc 窗口大小 * @return 返回窗口句柄 */ virtual HWND Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, bool isLayeredWindow = true, const UiRect& rc = UiRect(0, 0, 0, 0));


2 窗口管理类,对窗口统一管理

//map<窗口类名,map<窗口id,窗口指针>>, 如果同一类只有一个窗口,使用类名作为id
typedef std::map<std::wstring, std::map<std::wstring, WindowEx*>> WindowsMap; 
typedef std::list<WindowEx *> WindowList;


class WindowsManager
{
public:
	SINGLETON_DEFINE(WindowsManager);
	WindowsManager();
	virtual ~WindowsManager();

	//根据窗口类名和id注册窗口
	bool RegisterWindow(const std::wstring wnd_class_name, const std::wstring wnd_id, WindowEx *wnd);
	//根据窗口类名和id注销窗口
	void UnRegisterWindow(const std::wstring &wnd_class_name, const std::wstring &wnd_id, WindowEx *wnd);
	//根据窗口类名和id获取窗口
	WindowEx* GetWindow(const std::wstring &wnd_class_name, const std::wstring &wnd_id);
	//获取所有窗口
	WindowList GetAllWindows();
	//获取指定class对应的所有窗口
	WindowList GetWindowsByClassName(LPCTSTR classname);
	//关闭所有窗口
	void DestroyAllWindows();
	//设置禁止窗口创建
	void SetStopRegister(bool stop=true){stop_register_ = stop;}
	//是否禁止窗口创建
	bool IsStopRegister(){return stop_register_;}

	template<typename WindowType>
	static WindowType* SingletonShow(const std::wstring& window_id,int nParam=-1,bool bSHow=true,HWND hParent=NULL)
	{
		if (nParam > 0)
			kClass_Param_map[WindowType::kClassName] = nParam;


		WindowType *window = (WindowType*)(WindowsManager::GetInstance()->GetWindow(WindowType::kClassName, window_id));
		if (!window)
		{
			window = new WindowType;
			window->Create(hParent, WindowType::kClassName, WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX, 0);
			
			window->CenterWindow();
		
			if (bSHow)
			{
				window->ShowWindow();
			}
			
		}
		else
		{
			window->ActiveWindow();
		}

		return window;
	}

private:
	WindowsMap					windows_map_;	//所有窗口
	std::string					user_id_;
	bool						stop_register_;	//禁止窗口创建
public:
	static std::map<std::wstring, int> kClass_Param_map; // 窗口创建前,对应kClassName窗口中的参数,用此参数可以进行不同的初始化处理
};


其中,单例模板中,负责窗口创建

调用dulib窗口类创建函数, 创建默认duilib窗口

virtual HWND Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, bool isLayeredWindow = true, const UiRect& rc = UiRect(0, 0, 0, 0));


window = new WindowType; window->Create(hParent, WindowType::kClassName, WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX, 0);


3 窗口创建流程

以登录窗口创建为例,看看窗口创建流程

nim_comp::WindowsManager::SingletonShow<LoginForm>(LoginForm::kClassName);


?


?


在窗口创建Create中,RegisterWindowClass 注册窗口处理函数

bool Window::RegisterWindowClass()
{
	WNDCLASS wc = { 0 };
	wc.style = GetClassStyle();
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hIcon = NULL;
	wc.lpfnWndProc = Window::__WndProc;
	wc.hInstance = ::GetModuleHandle(NULL);
	wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = NULL;
	wc.lpszMenuName = NULL;
	std::wstring className = GetWindowClassName();
	wc.lpszClassName = className.c_str();
	ATOM ret = ::RegisterClass(&wc);
	ASSERT(ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS);
	return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
}

窗口处理函数

LRESULT CALLBACK Window::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    Window* pThis = NULL;
    if( uMsg == WM_NCCREATE ) {
        LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
        pThis = static_cast<Window*>(lpcs->lpCreateParams);
        pThis->m_hWnd = hWnd;
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
    }
    else {
        pThis = reinterpret_cast<Window*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
        if( uMsg == WM_NCDESTROY && pThis != NULL ) {
            LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
            ::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);
            if( pThis->m_bSubclassed ) pThis->Unsubclass();
            pThis->OnFinalMessage(hWnd);
            return lRes;
        }
    }

	if (pThis != NULL) {
        return pThis->HandleMessage(uMsg, wParam, lParam);
    } 
    else {
        return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}

其中,通过GWLP_USERDATA 记录窗口指针

typedef struct tagCREATESTRUCT
{
  LPVOID  lpCreateParams;  //指向将被用于创建窗口的数据的指针。  
  HANDLE  hInstance;       //标识了拥有新窗口的模块的模块实例的句柄。  
  HMENU   hMenu;           //标识了要被用于新窗口的菜单。如果是子窗口,则包含整数ID。  
  HWND    hwndParent;      //标识了拥有新窗口的窗口。如果新窗口是一个顶层窗口,这个参数可以为NULL。  
  int     cy;              //指定了新窗口的高。  
  int     cx;              //指定了新窗口的宽。  
  int     y;               //指定了新窗口的左上角的y轴坐标。  
  int     x;               //指定了新窗口的左上角的x轴坐标。 
  LONG    style;           //指定了新窗口的风格。  
  LPCSTR  lpszName;        //指向一个以null结尾的字符串,指定了新窗口的名字。  
  LPCSTR  lpszClass;       //指向一个以null结尾的字符串,指定了新窗口的Windows类名
  DWORD   dwExStyle;       //指定了新窗口的扩展风格。  
} CREATESTRUCT;


WM_GETMINMAXINFO 0x0024 36

WM_NCCREATE 非客户区创建消息 0x0081 129

WM_NCCALCSIZE 0x0083 131

WM_CREATE 0x0001

WM_STYLECHANGING 7C 124

WM_STYLECHANGED 7D 125

WM_WINDOWPOSCHANGING 0X46 70

WM_WINDOWPOSCHANGED 0X 46 71

窗口创建时 消息顺序,在WM_NCCREATE 时,保存 窗口指针 句柄等信息

if( uMsg == WM_NCCREATE ) { LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam); pThis = static_cast<Window*>(lpcs->lpCreateParams); pThis->m_hWnd = hWnd; ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis)); }


相关推荐

“版本末期”了?下周平衡补丁!国服最强5套牌!上分首选

明天,酒馆战棋就将迎来大更新,也聊了很多天战棋相关的内容了,趁此机会,给兄弟们穿插一篇构筑模式的卡组推荐!老规矩,我们先来看10职业胜率。目前10职业胜率排名与一周前基本类似,没有太多的变化。平衡补丁...

VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符&quot;

首先,程序中头文件的选择,要选择头文件,在文件中是没有对M_PI的定义的。选择:项目——>”XXX属性"——>配置属性——>C/C++——>预处理器——>预处理器定义,...

东营交警实名曝光一批酒驾人员名单 88人受处罚

齐鲁网·闪电新闻5月24日讯酒后驾驶是对自己和他人生命安全极不负责的行为,为守护大家的平安出行路,东营交警一直将酒驾作为重点打击对象。5月23日,东营交警公布最新一批饮酒、醉酒名单。对以下驾驶人醉酒...

Qt界面——搭配QCustomPlot(qt platform)

这是我第一个使用QCustomPlot控件的上位机,通过串口精确的5ms发送一次数据,再将读取的数据绘制到图表中。界面方面,尝试卡片式设计,外加QSS简单的配了个色。QCustomPlot官网:Qt...

大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写

老友相聚,仗剑江湖!《大话西游2》2021全民PK季4月激燃打响,各PK玩法鏖战齐开,零门槛参与热情高涨。PK季期间,不仅各种玩法奖励丰厚,参与PK趣闻录活动,投稿自己在PK季遇到的趣事,还有机会带走...

测试谷歌VS Code AI 编程插件 Gemini Code Assist

用ClaudeSonnet3.7的天气测试编码,让谷歌VSCodeAI编程插件GeminiCodeAssist自动编程。生成的文件在浏览器中的效果如下:(附源代码)VSCode...

顾爷想知道第4.5期 国服便利性到底需优化啥?

前段时间DNF国服推出了名为“阿拉德B计划”的系列改版计划,截至目前我们已经看到了两项实装。不过关于便利性上,国服似乎还有很多路要走。自从顾爷回归DNF以来,几乎每天都在跟我抱怨关于DNF里面各种各样...

掌握Visual Studio项目配置【基础篇】

1.前言VisualStudio是Windows上最常用的C++集成开发环境之一,简称VS。VS功能十分强大,对应的,其配置系统较为复杂。不管是对于初学者还是有一定开发经验的开发者来说,捋清楚VS...

还嫌LED驱动设计套路深?那就来看看这篇文章吧

随着LED在各个领域的不同应用需求,LED驱动电路也在不断进步和发展。本文从LED的特性入手,推导出适合LED的电源驱动类型,再进一步介绍各类LED驱动设计。设计必读:LED四个关键特性特性一:非线...

Visual Studio Community 2022(VS2022)安装图文方法

直接上步骤:1,首先可以下载安装一个VisualStudio安装器,叫做VisualStudioinstaller。这个安装文件很小,很快就安装完成了。2,打开VisualStudioins...

Qt添加MSVC构建套件的方法(qt添加c++11)

前言有些时候,在Windows下因为某些需求需要使用MSVC编译器对程序进行编译,假设我们安装Qt的时候又只是安装了MingW构建套件,那么此时我们该如何给现有的Qt添加一个MSVC构建套件呢?本文以...

Qt为什么站稳c++GUI的top1(qt c)

为什么现在QT越来越成为c++界面编程的第一选择,从事QT编程多年,在这之前做C++界面都是基于MFC。当时为什么会从MFC转到QT?主要原因是MFC开发界面想做得好看一些十分困难,引用第三方基于MF...

qt开发IDE应该选择VS还是qt creator

如果一个公司选择了qt来开发自己的产品,在面临IDE的选择时会出现vs或者qtcreator,选择qt的IDE需要结合产品需求、部署平台、项目定位、程序猿本身和公司战略,因为大的软件产品需要明确IDE...

Qt 5.14.2超详细安装教程,不会来打我

Qt简介Qt(官方发音[kju:t],音同cute)是一个跨平台的C++开库,主要用来开发图形用户界面(GraphicalUserInterface,GUI)程序。Qt是纯C++开...

Cygwin配置与使用(四)——VI字体和颜色的配置

简介:VI的操作模式,基本上VI可以分为三种状态,分别是命令模式(commandmode)、插入模式(Insertmode)和底行模式(lastlinemode),各模式的功能区分如下:1)...

取消回复欢迎 发表评论: