MFC 模态对话框的实现原理
- 格式:docx
- 大小:46.88 KB
- 文档页数:8
1. 模态对话框
在涉及GUI程序开发的过程中,常常有模态对话框以及非模态对话框的概念
模态对话框:在子界面活动期间,父窗口是无法进行消息响应。独占用户输入
非模态对话框:各窗口之间不影响
主要区别:非模态对话框与APP共用消息循环,不会独占用户。
模态对话框独占用户输入,其他界面无法响应
在用户层的主要逻辑如下:
1 TestDlgdlg;
2
3 if (dlg.DoModal() == IDOK)
4 {
5 //处理完毕后的操作
6 }
7 .......//后续处理
在具体实现中,有如下几个步骤:
1. 让父窗口失效EnableWindow(parentWindow, FALSE)
2. 建立模态对话框自己的消息循环(RunModalLoop)
3. 直至接收关闭消息,消息循环终止,并销毁窗口。
01 INT_PTR CDialog::DoModal()
02 {
03 //对话框资源加载
04 ......
05
06 //在创建模态窗口之前先让父窗口失效,不响应键盘、鼠标产生的消息
07 HWND hWndParent = PreModal();
08 AfxUnhookWindowCreate();
09 BOOL bEnableParent = FALSE;
10
11 if (hWndParent&&hWndParent != ::GetDesktopWindow() && ::IsWindowEnabled(hWndParent))
12 {
13 ::EnableWindow(hWndParent, FALSE);
14 bEnableParent = TRUE;
15 .......
16 }
17
18 //创建模态窗口,并进行消息循环,若窗口不关闭,则循环不退出 19 AfxHookWindowCreate(this);
20 VERIFY(RunModalLoop(dwFlags) == m_nModalResult);
21
22 //窗口关闭,销毁窗口
23 DestroyWindow();
24 PostModal();
25
26 //释放资源,并让父窗口有效
27 pMainWnd->EnableWindow(TRUE);
28
29 //返回
30 return m_nModalResult;
31 }
2. 模态窗口中的消息循环
01 int CWnd::RunModalLoop(DWORD dwFlags)
02 {
03 //要检查窗口状态是否是模态窗口
04 //若状态一直为模态,则一直进行消息循环
05 for (;;)
06 {
07 ASSERT(ContinueModal());
08
09 // phase1: check to see if we can do idle work
10 while (bIdle&&
11 !::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE)) 12 {
13 ASSERT(ContinueModal());
14
15 // show the dialog when the message queue goes idle 16 if (bShowIdle)
17 {
18 ShowWindow(SW_SHOWNORMAL);
19 UpdateWindow();
20 bShowIdle = FALSE;
21 }
22
23 // call OnIdle while in bIdle state
24 if (!(dwFlags& MLF_NOIDLEMSG) &&hWndParent != NULL &&lIdleCount == 0)
25 {
26 // send WM_ENTERIDLE to the parent
27 ::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);
28 }
29 if ((dwFlags& MLF_NOKICKIDLE) ||
30 !SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++))
31 {
32 // stop idle processing next time
33 bIdle = FALSE;
34 }
35 }
36
37 //在有消息的情况下取消息处理
38 do
39 {
40 ASSERT(ContinueModal());
41
42 // pump message, but quit on WM_QUIT
43 if (!AfxPumpMessage())
44 {
45 AfxPostQuitMessage(0);
46 return -1;
47 }
48
49 // show the window when certain special messages rec'd 50 if (bShowIdle&&
51 (pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN))
52 {
53 ShowWindow(SW_SHOWNORMAL);
54 UpdateWindow();
55 bShowIdle = FALSE;
56 }
57
58 if (!ContinueModal())
59 goto ExitModal;
60
61 // reset "no idle" state after pumping "normal" message 62 if (AfxIsIdleMessage(pMsg))
63 {
64 bIdle = TRUE;
65 lIdleCount = 0;
66 }
67
68 } while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));
69 }
70
71 ExitModal:
72 m_nFlags&= ~(WF_MODALLOOP|WF_CONTINUEMODAL);
73 return m_nModalResult;