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”: 未声明的标识符"
-
首先,程序中头文件的选择,要选择头文件,在文件中是没有对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)...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- “版本末期”了?下周平衡补丁!国服最强5套牌!上分首选
- VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符"
- 东营交警实名曝光一批酒驾人员名单 88人受处罚
- Qt界面——搭配QCustomPlot(qt platform)
- 大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写
- 测试谷歌VS Code AI 编程插件 Gemini Code Assist
- 顾爷想知道第4.5期 国服便利性到底需优化啥?
- 掌握Visual Studio项目配置【基础篇】
- 还嫌LED驱动设计套路深?那就来看看这篇文章吧
- Visual Studio Community 2022(VS2022)安装图文方法
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)