TA的每日心情 | 奋斗 2022-7-4 09:45 |
---|
签到天数: 28 天 [LV.4]偶尔看看III
版主
- 积分
- 5515
|
经常有人问题怎么在SOUI中打开模态窗口,又如果打开非模态窗口。
首先要搞明白什么是模态窗口,什么是非模态窗口。
所谓非模态窗口,其实是相对于模态窗口而言的。基本质上就是通过CreateWindow这个API创建出来的一个popup窗口,和主窗口共享消息循环。
说到消息循环,可能有人并不知道消息循环是干什么的。
我们先看一个VS创建最基本的Win32工程的main函数里的消息循环:
- MSG msg;
- // 主消息循环:
- while (GetMessage(&msg, nullptr, 0, 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
复制代码 从上面代码可以看出,消息循环就是一个简单的while循环。
消息循环不断的获取UI线程的消息,然后再将消息转发到目标窗口。
什么是消息的目标窗口?就是程序中使用SendMessage,PostMessage的第一个参数。
理解了消息循环,就应该知道非模态窗口其实就是一个普通的弹出窗口,非模态窗口处理的消息都是主线程的消息循环Dispatch过来的消息。
那么什么是模态窗口呢?
模态窗口就是有自己的消息循环,不使用主消息循环。
为什么要使用模态窗口呢?
其实这个问题很简单,比如程序需要弹出一个MessageBox,在用户确认以前,代码就一直在这里等待。如果不使用模态窗口,这个逻辑就会非常复杂:弹出窗口是一个过程,响应窗口的点击事件是另一个过程,代码处理很分散。使用模态窗口则可以直接在一个函数里实现。
说了那么多,SOUI里如何使用模态窗口及非模态窗口呢?
模态窗口很简单,SOUI包装了SHostDialog,它和MFC的CDialog类似,直接调用它的DoModal就可以了。
例如,你定义了一个布局文件,资源ID为:xml:modaldlg
模态对话框可以是
- SHostDialog dlg(L"xml:modaldlg");
- int nRet = dlg.DoModal();
复制代码 虽然非模态窗口本质就是一个弹出窗口,但是非模态窗口会有一个生命周期管理问题。
很多人经常犯的一个错误就是在一个函数的局部变量中声明一个非模态窗口,然后Create出来,然后就问为什么程序崩溃了。
看到这样的问题我也是崩溃的。这些人这是连win32基础都没有啊。
明眼人一看就知道,你窗口是创建出来了,但是你的窗口对像在函数退出的时候已经析构了,不崩溃才怪。
所以非模态窗口一个重要的问题就是生命周期的管理。
通常一个非模态窗口需要new出一个SHostWnd对象。new出来就涉及到delete。什么时候delete呢?
如果一个非模态窗口和主窗口是相同的生命周期还好办,直接在主窗口的析构中DestroyWindow再delete就完了。
如果和主窗口生命周期不同怎么办?
例如我需要任意时候创建一个窗口,在窗口点击“关闭”就要能够delete窗口对象。
这个时候最好的办法就是继承ShostWnd再重载void ShostWnd::OnFinalMessage(HWND)方法。
例如:
- class CNonModalDlg: public SHostWnd
- {
- public:
- CNonModalDlg(LPCWSTR resId):SHostWnd(resId){}
- protected:
- virtual void OnFinalMessage(HWND) override
- {
- delete this;
- }
- };
复制代码 然后就可以用下面代码来创建及销毁窗口了。
- //创建窗口:
- CNonModalDlg *pDlg = new CNonModalDlg(L"xml:xxxx");
- pDlg->Create();
- pDlg->ShowWindow(SW_SHOW);
- //销毁窗口
- pDlg->DestroyWindow();
- pDlg = NULL;
复制代码
|
|