MFC 模态对话框的实现原理

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

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;

相关文档
最新文档