SOUI官方论坛

 找回密码
 立即注册
查看: 7331|回复: 5

模态窗口与非模态窗口

[复制链接]
  • TA的每日心情
    奋斗
    2022-7-4 09:45
  • 签到天数: 28 天

    [LV.4]偶尔看看III

    59

    主题

    590

    帖子

    5515

    积分

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    5515

    突出贡献优秀版主

    发表于 2019-10-31 11:12:35 | 显示全部楼层 |阅读模式
    经常有人问题怎么在SOUI中打开模态窗口,又如果打开非模态窗口。
    首先要搞明白什么是模态窗口,什么是非模态窗口。
    所谓非模态窗口,其实是相对于模态窗口而言的。基本质上就是通过CreateWindow这个API创建出来的一个popup窗口,和主窗口共享消息循环。
    说到消息循环,可能有人并不知道消息循环是干什么的。
    我们先看一个VS创建最基本的Win32工程的main函数里的消息循环:
    1.     MSG msg;
    2.     // 主消息循环:
    3.     while (GetMessage(&msg, nullptr, 0, 0))
    4.     {
    5.         TranslateMessage(&msg);
    6.         DispatchMessage(&msg);
    7.     }
    复制代码
    从上面代码可以看出,消息循环就是一个简单的while循环。
    消息循环不断的获取UI线程的消息,然后再将消息转发到目标窗口。
    什么是消息的目标窗口?就是程序中使用SendMessage,PostMessage的第一个参数。

    理解了消息循环,就应该知道非模态窗口其实就是一个普通的弹出窗口,非模态窗口处理的消息都是主线程的消息循环Dispatch过来的消息。
    那么什么是模态窗口呢?
    模态窗口就是有自己的消息循环,不使用主消息循环。
    为什么要使用模态窗口呢?
    其实这个问题很简单,比如程序需要弹出一个MessageBox,在用户确认以前,代码就一直在这里等待。如果不使用模态窗口,这个逻辑就会非常复杂:弹出窗口是一个过程,响应窗口的点击事件是另一个过程,代码处理很分散。使用模态窗口则可以直接在一个函数里实现。

    说了那么多,SOUI里如何使用模态窗口及非模态窗口呢?
    模态窗口很简单,SOUI包装了SHostDialog,它和MFC的CDialog类似,直接调用它的DoModal就可以了。
    例如,你定义了一个布局文件,资源ID为:xml:modaldlg
    模态对话框可以是
    1. SHostDialog dlg(L"xml:modaldlg");
    2. int nRet = dlg.DoModal();
    复制代码
    虽然非模态窗口本质就是一个弹出窗口,但是非模态窗口会有一个生命周期管理问题。
    很多人经常犯的一个错误就是在一个函数的局部变量中声明一个非模态窗口,然后Create出来,然后就问为什么程序崩溃了。
    看到这样的问题我也是崩溃的。这些人这是连win32基础都没有啊。
    明眼人一看就知道,你窗口是创建出来了,但是你的窗口对像在函数退出的时候已经析构了,不崩溃才怪。
    所以非模态窗口一个重要的问题就是生命周期的管理。
    通常一个非模态窗口需要new出一个SHostWnd对象。new出来就涉及到delete。什么时候delete呢?
    如果一个非模态窗口和主窗口是相同的生命周期还好办,直接在主窗口的析构中DestroyWindow再delete就完了。
    如果和主窗口生命周期不同怎么办?
    例如我需要任意时候创建一个窗口,在窗口点击“关闭”就要能够delete窗口对象。
    这个时候最好的办法就是继承ShostWnd再重载void ShostWnd::OnFinalMessage(HWND)方法。
    例如:
    1. class CNonModalDlg: public SHostWnd
    2. {
    3. public:
    4.     CNonModalDlg(LPCWSTR resId):SHostWnd(resId){}

    5. protected:
    6. virtual void OnFinalMessage(HWND) override
    7. {
    8. delete this;
    9. }
    10. };
    复制代码
    然后就可以用下面代码来创建及销毁窗口了。
    1. //创建窗口:
    2. CNonModalDlg *pDlg = new CNonModalDlg(L"xml:xxxx");
    3. pDlg->Create();
    4. pDlg->ShowWindow(SW_SHOW);

    5. //销毁窗口
    6. pDlg->DestroyWindow();
    7. pDlg = NULL;
    复制代码


  • TA的每日心情
    开心
    前天 22:51
  • 签到天数: 946 天

    [LV.10]以坛为家III

    581

    主题

    1343

    帖子

    2万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    28876
    发表于 2019-10-31 11:25:43 | 显示全部楼层
    谢谢楼主分享,抓紧学习

    该用户从未签到

    4

    主题

    67

    帖子

    1388

    积分

    06:00合体期

    Rank: 6Rank: 6

    积分
    1388
    发表于 2019-10-31 11:58:56 | 显示全部楼层
    老大 问一下 整个XML上的控件都无法设置tip有可能是什么原因导致的呢
  • TA的每日心情
    奋斗
    2022-7-4 09:45
  • 签到天数: 28 天

    [LV.4]偶尔看看III

    59

    主题

    590

    帖子

    5515

    积分

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    5515

    突出贡献优秀版主

     楼主| 发表于 2019-10-31 14:14:33 | 显示全部楼层
    lemon 发表于 2019-10-31 11:58
    老大 问一下 整个XML上的控件都无法设置tip有可能是什么原因导致的呢

    不清楚。文本控件这样的不响应鼠标消息的控件是不会显示tip的。
  • TA的每日心情
    开心
    前天 22:51
  • 签到天数: 946 天

    [LV.10]以坛为家III

    581

    主题

    1343

    帖子

    2万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    28876
    发表于 2019-11-19 10:51:02 | 显示全部楼层
    这个是一个源码实例:
    soui弹出模态对话框和非模态对话框【新手入门】
    http://www.soui.vip/forum.php?mo ... d=327&fromuid=1
    (出处: SOUI官方论坛)

    该用户从未签到

    1

    主题

    35

    帖子

    43

    积分

    22:00筑基期

    Rank: 1

    积分
    43
    发表于 2020-4-16 18:32:38 | 显示全部楼层
    谢谢分享,看看
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|SOUI官方论坛

    GMT+8, 2024-5-18 15:13

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表