MFC 模态对话框的实现原理

参考自MFC 模态对话框的实现原理 - 西昆仑 - OSCHINA - 中文开源技术交流社区

1. 模态对话框

在涉及 GUI 程序开发的过程中,常常有模态对话框以及非模态对话框的概念

模态对话框:在模态对话框活动期间,父窗口是无法进行消息响应,独占用户输入;
非模态对话框:各窗口之间不影响。

主要区别:

非模态对话框与 APP 共用消息循环,不会独占用户;
模态对话框独占用户输入,其他界面无法响应。

在用户层的主要逻辑如下:

TestDlg dlg;if (dlg.DoModal() == IDOK)
{//处理完毕后的操作
}
.......//后续处理

在具体实现中,有如下几个步骤:
1. 让父窗口失效 EnableWindow (parentWindow, FALSE)
2. 建立模态对话框自己的消息循环(RunModalLoop)
3. 直至接收关闭消息,消息循环终止,并销毁窗口。

INT_PTR CDialog::DoModal()
{//对话框资源加载......//在创建模态窗口之前先让父窗口失效,不响应键盘、鼠标产生的消息HWND hWndParent = PreModal();AfxUnhookWindowCreate();BOOL bEnableParent = FALSE;if (hWndParent && hWndParent != ::GetDesktopWindow() && ::IsWindowEnabled(hWndParent)){::EnableWindow(hWndParent, FALSE);bEnableParent = TRUE;.......}//创建模态窗口,并进行消息循环,若窗口不关闭,则循环不退出AfxHookWindowCreate(this);VERIFY(RunModalLoop(dwFlags) == m_nModalResult);//窗口关闭,销毁窗口DestroyWindow();PostModal();//释放资源,并让父窗口有效pMainWnd->EnableWindow(TRUE);//返回return m_nModalResult;
}

2. 模态窗口中的消息循环

int CWnd::RunModalLoop(DWORD dwFlags)
{//要检查窗口状态是否是模态窗口//若状态一直为模态,则一直进行消息循环for (;;){ASSERT(ContinueModal());// phase1: check to see if we can do idle workwhile (bIdle &&!::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE)){ASSERT(ContinueModal());// show the dialog when the message queue goes idleif (bShowIdle){ShowWindow(SW_SHOWNORMAL);UpdateWindow();bShowIdle = FALSE;}// call OnIdle while in bIdle stateif (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0){// send WM_ENTERIDLE to the parent::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);}if ((dwFlags & MLF_NOKICKIDLE) ||!SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++)){// stop idle processing next timebIdle = FALSE;}}//在有消息的情况下取消息处理do{ASSERT(ContinueModal());// pump message, but quit on WM_QUITif (!AfxPumpMessage()){AfxPostQuitMessage(0);return -1;}// show the window when certain special messages rec'dif (bShowIdle &&(pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN)){ShowWindow(SW_SHOWNORMAL);UpdateWindow();bShowIdle = FALSE;}if (!ContinueModal())goto ExitModal;// reset "no idle" state after pumping "normal" messageif (AfxIsIdleMessage(pMsg)){bIdle = TRUE;lIdleCount = 0;}} while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));}ExitModal:m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL);return m_nModalResult;
}

GetMessage 与 PeekMessage 的区别:
GetMessage: 用于从消息队列读取消息。若队列中没有消息,GetMessage 将导致线程阻塞。
PeekMessage: 检测队列中是否有消息,并立即返回,不会导致阻塞。

3. APP 中的消息循环

//thrdcore.cpp   
// main running routine until thread exits   
int CWinThread::Run()  
{  // for tracking the idle time state   BOOL bIdle = TRUE;  LONG lIdleCount = 0;  //消息读取乃至分发 当为WM_QUIT时,退出循环 for (;;)  {  //检查是否为空闲时刻while (bIdle &&  !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))  {  // call OnIdle while in bIdle state   if (!OnIdle(lIdleCount++))  bIdle = FALSE; // assume "no idle" state   }  //有消息,读消息并分发 do  {  // pump message, but quit on WM_QUIT   if (!PumpMessage())  return ExitInstance();  // reset "no idle" state after pumping "normal" message   if (IsIdleMessage(&m_msgCur))  {  bIdle = TRUE;  lIdleCount = 0;  }  }   while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));  }  
}

4. 模态对话框中局部消息循环和 APP 全局消息循环的关系

4.1 APP 消息循环和模态对话框中局部消息循环的关系

根据上图可以看出,在 APP 的消息循环再派发 ONOK 消息后,调用 ModalDlg 的响应函数,pWnd->OnOk (); 在该消息中,
会 进入模态对话框的消息循环,除非将模态对话框关闭,否则 APP 的 DispatchMessage 函数一直出不来。

一旦创建了模态对话框,进行局部消息循环,那么 APP 的消息循环就被阻断。整个程序的消息循环有模态对话框中得消息循环取代。所以给父窗口发送的非窗口消息,一样可以响应。

由于局部消息循环只在对话框中的一个响应函数中,而全局的消息循环也被阻断,局部循环一直运行,如果用户不进行处理并关闭模态对话框,该循环会一直不退出。其他对话框也得不到处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/19501.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaEE初阶多线程 (5)

1.锁的策略 1.1锁的策略是什么 这个锁的策略可以理解为,一种做法,相当于当你遇到锁竞争,加锁解锁,的情况你会怎么做。 乐观锁可以理解为疫情的时候比较乐观就买了最基本的物资, 买的时候非常方便 1.2乐观锁 当效率…

Wireshark抓包后的报文太大,如何拆分?

背景:抓包获取到一个400多兆的网络数据包.pcapng文件,使用wireshark软件可以正常打开。但需要把文件导出为.json文件,从而方便对报文内容做过滤分析。使用wireshark自带的导出功能导出后发现生成的.json文件大小为2G多,使用notepa…

Python实现定时任务的方式

大家好,在当今数字化的时代,定时任务的需求在各种应用场景中频繁出现。无论是数据的定时更新、周期性的任务执行,还是特定时间点的操作触发,Python 都为我们提供了强大而灵活的手段来实现这些定时任务。当我们深入探索 Python 的世…

【机器学习】AI大模型的探索—浅谈ChatGPT及其工作原理

📝个人主页:哈__ 期待您的关注 目录 📚介绍ChatGPT 1.1 什么是ChatGPT 1.2 ChatGPT的应用场景 💡基础概念 1. 人工智能和机器学习 1.1 人工智能(AI)简介 1.2 机器学习(ML)简…

【面结构光三维重建】0.基于openCV实现相机的标定

1.标定结果 2.相机标定原理 相机标定是计算机视觉和机器视觉领域中的重要技术,用于确定相机成像的几何关系和畸变特性,以提高成像的精度和稳定性。该技术广泛应用于三维重建、机器人视觉、自动驾驶等领域。 世界坐标系:由用户定义的三维世界坐标系,描述物体和相机在真实世…

第二十五章新增H5基础(以及视频~兼容)

1.HTML5中新增布局标签 HTML5新增了页眉&#xff0c;页脚&#xff0c;内容块等文档结构相关标签&#xff0c;可以使文档结构更加清晰明了。 1.新增的结构标签 1、<header>标签 定义文档或者文档中内容块的页眉。通常可以包含整个页面或一个内容区域的标题&#xff0c…

GEYA格亚GRT8-M多种功能时间继电器交流AC220V DC24V延时断开小巧

品牌 GEYA 型号 GRT8-M1 AC/DC12-240 产地 中国大陆 颜色分类 GRT8-M1 A220,GRT8-M1 AC/DC12-240,GRT8-M2 A220,GRT8-M2 AC/DC12-240 GRT8-M&#xff0c;多功能型&#xff0c;时间继电器&#xff1a;LED指示灯&#xff0c;触头容量大&#xff0c;电压超宽&#xff0c;阻…

2024.5.29晚训参考代码

因为本套题没有BFS例题&#xff0c;所以我先把BFS模板放着 #include<bits/stdc.h> using namespace std; int n,m;//n*m的棋盘 int dis[402][402]; bool vis[402][402]; int X[]{-2,-2,-1,-1,1,1,2,2};//偏移量的表 int Y[]{-1,1,-2,2,-2,2,-1,1};//定义一个数组&…

PDF盖骑缝章

在PDF文件上加盖骑缝章&#xff0c;您可以采取以下几种方法之一&#xff1a; 使用Adobe Acrobat&#xff1a; 打开Adobe Acrobat软件&#xff0c;加载PDF文件。在工具栏选择“工具”选项&#xff0c;找到“骑缝章”或“印章”工具。选择或上传您的骑缝章图片&#xff0c;将其放…

Dify数据库结构导出到PowerDesigner

即刻关注&#xff0c;获取更多 关注公众号 N学无止界 获取更多 Dify数据库结构导出到PowerDesigner Dify简介 Dify简介 欢迎使用 Dify Dify 是一款开源的大语言模型(LLM) 应用开发平台。它融合了后端即服务&#xff08;Backend as Service&#xff09;和 LLMOps 的理念&…

FFmpeg开发笔记(三十一)使用RTMP Streamer开启APP直播推流

RTMP Streamer是一个安卓手机端的开源RTMP直播推流框架&#xff0c;可用于RTMP直播和RTSP直播&#xff0c;其升级版还支持SRT直播&#xff08;腾讯视频云就采用SRT协议&#xff09;。RTMP Streamer支持的视频编码包括H264、H265、AV1等等&#xff0c;支持的音频编码包括AAC、G7…

AI绘画Stable Diffusion【隐藏文字】:将艺术字隐藏在国风云雾山水图中

大家好&#xff0c;我是灵魂画师向阳 今天我们分享一下用AI绘画工具Stable Diffusion制作网上很火的隐藏文字。这里以将艺术字隐藏在国风云雾山水图为例进行讲解&#xff0c;下面我们就来看看吧。 一. 艺术字隐藏在国风云雾山水图中制作方法 【第一步】&#xff1a;制作底图…

使用Python爬取华为市场游戏类APP应用

文章目录 1. 写在前面2. 接口分析3. 爬虫开发4. 下载链接获取 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守…

uni-app实现页面通信EventChannel

uni-app实现页面通信EventChannel 之前使用了EventBus的方法实现不同页面组件之间的一个通信&#xff0c;在uni-app中&#xff0c;我们也可以使用uni-app API —— uni.navigateTo来实现页面间的通信。注&#xff1a;2.8.9 支持页面间事件通信通道。 1. 向被打开页面传送数据…

JavaScript笔记二-JavaScript基础语法

1、标识符 命名规则 第一个字符必须是一个字母、下划线&#xff08; _ &#xff09;或一个美元符号&#xff08; $ &#xff09;。其它字符可以是字母、下划线、美元符号或数字。按照惯例&#xff0c;ECMAScript 标识符采用驼峰命名法。标识符不能是关键字和保留字符。 2、字…

2022年全国职业院校技能大赛高职组“信息安全管理与评估”赛项第三阶段任务书

第三阶段竞赛项目试题 本文件为信息安全管理与评估项目竞赛-第三阶段试题。根据信息安全管理与评估项目技术文件要求&#xff0c;第三阶段为夺旗挑战CTF&#xff08;网络安全渗透&#xff09;。 本次比赛时间为180分钟。 介绍 夺旗挑战赛&#xff08;CTF&#xff09;的目标…

开发语言Java+前端框架Vue+后端框架SpringBoot开发的ADR药物不良反应监测系统源码 系统有哪些优势?

开发语言Java前端框架Vue后端框架SpringBoot开发的ADR药物不良反应监测系统源码 系统有哪些优势&#xff1f; ADR药物不良反应监测系统具有多个显著的优势&#xff0c;这些优势主要体现在以下几个方面&#xff1a; 一、提高监测效率与准确性&#xff1a; 通过自动化的数据收集…

在热力图基础上寻找所有峰值位置

文章目录 概要代码概要 理解热力图:首先,了解热力图是什么以及它代表了什么信息至关重要。热力图通常是二维的,其中每个像素的颜色表示该位置的数值大小。较亮的颜色通常表示较高的数值,而较暗的颜色表示较低的数值。 阈值处理:根据问题的要求,可能需要对热力图进行阈值处…

吴恩达2022机器学习专项课程C2W2:实验SoftMax

目录 Softmax函数1.简述2.Numpy实现softmax函数 softmax成本函数softmax应用于神经网络1.自定义数据集2.构建模型3.使用模型预测4.改良模型代码&#xff08;softmax转换输出&#xff09; Softmax函数 1.简述 在 Softmax 回归和带有 Softmax 输出的神经网络中&#xff0c;模型…

小程序如何更换营业执照

​因为商家经营业务的变更&#xff0c;尤其是之前的营业执照注销等原因&#xff0c;导致要求更换小程序主体。下面就具体介绍如何进行变更。 1. 登录mp.weixin.qq.com&#xff0c;找到设置->基本设置&#xff0c;在主体信息字段&#xff0c;点击小程序主体变更。主体变更分…