MFC模态对话框与非模态对话框

本文详细介绍了MFC中的模态对话框与非模态对话框的区别及其在Windows消息处理机制中的实现方式。模态对话框会阻止用户与程序其他部分的交互,直到关闭,而无模态对话框则允许用户同时操作其他窗口。在MFC中,CDialog类是对话框的基础,DoModal()函数用于创建模态对话框并执行消息循环。数据交换和验证通过CDataExchange类及DDX_系列函数简化操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对话框经常被使用,因为对话框可以从模板创建,而对话框模板是可以使用资源编辑器方便地进行编辑的。

一,模态与非模态对话框
1.
模态对话框
   
一个模态对话框是一个有系统菜单、标题栏、边线等的弹出式窗口。在创建对话框时指定WS_POPUP,WS_SYSMENU, WS_CAPTION DS_MODALFRAME风格。即使没有指定WS_VISIBLE风格,模

式对话框也会被显示。创建对话框窗口时,将发送WM_INITDIALOG消息(如果指定对话框的DS_SETFONT风格,还有WM_SETFONT消息)给对话框过程。
   
对话框窗口被创建之后,Windows使得它成为一个激活的窗口,它保持激活直到对话框过程调用::EndDialog函数结束对话框的运行或者Windows激活另一个应用程序为止,在激活时,用户

或者应用程序不可以激活它的所属窗口(Owner window)。从某个窗口创建一个模态对话框时,Windows自动地禁止使用(Disable)这个窗口和它的所有子窗口,直到该模态对话框被关闭和

销毁。虽然对话框过程可以Enable所属窗口,但是这样做就失去了模态对话框的作用,所以不鼓励这样做。
    Windows
创建模态对话框时,给当前捕获鼠标输入的窗口(如果有的话)发送消息WM_CANCLEMODE。收到该消息后,应用程序应该终止鼠标捕获(Release the mouse capture)以便于用户能

把鼠标移到模态对话框;否则由于Owner窗口被禁止,程序将失去鼠标输入。
  
为了处理模态对话框的消息,Windows开始对话框自身的消息循环,暂时控制整个应用程序的消息队列。如果Windows收到一个非对话框消息时,则它把消息派发给适当的窗口处理;如果收

到了WM_QUIT消息,则把该消息放回应用程序的消息队列里,这样应用程序的主消息循环最终能处理这个消息。
  
当应用程序的消息队列为空时,Windows发送WM_ENTERIDLE消息给Owner窗口。在对话框运行时,程序可以使用这个消息进行后台处理,当然应该注意经常让出控制给模态对话框,以便它能

接收用户输入。如果不希望模态对话框发送 WM_ENTERIDlE消息,则在创建模态对话框时指定DS_NOIDLEMSG风格。
  
一个应用程序通过调用::EndDialog函数来销毁一个模态对话框。一般情况下,当用户从系统菜单里选择了关闭(Close)命令或者按下了确认(OK)或取消(CANCLE)按钮,::EndDialog

被对话框过程所调用。调用::EndDialog时,指定其参数nResult的值,Windows将在销毁对话框窗口后返回这个值,一般,程序通过返回值判断对话框窗口是否完成了任务或者被用户取消。

 

2. 无模态对话框
  
一个无模态对话框是一个有系统菜单、标题栏、边线等的弹出式窗口。在创建对话框模板时指定WS_POPUPWS_CAPTIONWS_BORDERWS_SYSMENU风格。如果没有指定WS_VISIBLE风格,无

模态对话框不会自动地显示出来。一个无模态对话框既不会禁止所属窗口,也不会给它发送消息(WM_ENTERIDlE)。当创建一个无模态对话框时,Windows使它成为活动窗口,但用户或者程序

可以随时改变和设置活动窗口。如果对话框失去激活,那么即使所属窗口是活动的,在Z轴顺序上,它仍然在所属窗口之上。
  
应用程序负责获取和派发输入消息给对话框。大部分应用程序使用主消息循环来处理,但是为了用户可以使用键盘在控制窗口之间移动或者选择控制窗口,应用程序应该调

::IsDialogMessage函数。
  
这里,顺便解释::IsDialogMessage函数。虽然该函数是为无模态对话框设计的,但是任何包含了控制子窗口的窗口都可以调用它,用来实现类似于对话框的键盘选择操作。
::IsDialogMessage处理一个消息时,它检查键盘消息并把它们转换成相应对话框的选择命令。例如,当Tab 键被压下时,下一个或下一组控制被选中,当Down Arrow键按下后,一组控制中

的下一个控制被选择。::IsDialogMessage完成了所有必要的消息转换和消息派发,所以该函数处理的消息一定不要传递给TranslateMessageDispatchMessage处理。一个无模态对话框不能

像模态对话框那样返回一个值给应用程序。但是对话框过程可以使用::SendMessage给所属窗口传递信息。
  
在应用程序结束之前,它必须销毁所有的无模态对话框。使用::DestroyWindow销毁一个无模态对话框,不是使用::EndDiaLog。一般来说,对话框过程响应用户输入,如用户选择了取消

按钮,则调用::DestroyWindow;如果用户没有有关动作,则应用程序必须调用::DestroyWindow

 

二,对话框的MFC实现
1.
MFC中,对话框窗口的功能主要由CWndCDialog两个类实现。

[cpp] view plaincopy

1.  class CDialog : public CWnd  

2.  {  

3.      DECLARE_DYNAMIC(CDialog)  

4.  //初始化函数  

5.  public:  

6.      virtual BOOL Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL);  

7.      virtual BOOL Create(UINT nIDTemplate, CWnd* pParentWnd = NULL);  

8.      virtual BOOL CreateIndirect(LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd = NULL,void* lpDialogInit = NULL);  

9.      virtual BOOL CreateIndirect(HGLOBAL hDialogTemplate, CWnd* pParentWnd = NULL);  

10.         BOOL InitModalIndirect(LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd = NULL,void* lpDialogInit = NULL);  

11.     BOOL InitModalIndirect(HGLOBAL hDialogTemplate, CWnd* pParentWnd = NULL);  

12. //构造函数  

13. public:  

14.         CDialog();  

15.     explicit CDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL);  

16.     explicit CDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL);  

17. // 操作函数  

18. public:  

19.     // modal processing  

20.     virtual INT_PTR DoModal();  

21.   

22.     // support for passing on tab control - use 'PostMessage' if needed  

23.     void NextDlgCtrl() const;  

24.     void PrevDlgCtrl() const;  

25.     void GotoDlgCtrl(CWnd* pWndCtrl);  

26.   

27.     // default button access  

28.     void SetDefID(UINT nID);  

29.     DWORD GetDefID() const;  

30.   

31.     // termination  

32.     void EndDialog(int nResult);  

33.   

34. //重载函数  

35. protected:  

36.     virtual void OnOK();  

37.     virtual void OnCancel();  

38. public:  

39.     virtual BOOL OnInitDialog();  

40.     virtual void OnSetFont(CFont* pFont);  

41. public:  

42.     virtual ~CDialog();  

43.     virtual BOOL PreTranslateMessage(MSG* pMsg);  

44.     virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo);  

45.     virtual BOOL CheckAutoCenter();  

46.   

47. protected:  

48.     UINT m_nIDHelp;                 // Help ID (0 for none, see HID_BASE_RESOURCE)  

49.     LPCTSTR m_lpszTemplateName;     // name or MAKEINTRESOURCE  

50.     HGLOBAL m_hDialogTemplate;      // indirect (m_lpDialogTemplate == NULL)  

51.     LPCDLGTEMPLATE m_lpDialogTemplate;  // indirect if (m_lpszTemplateName == NULL)  

52.     void* m_lpDialogInit;           // DLGINIT resource data  

53.     CWnd* m_pParentWnd;             // parent/owner window  

54.     HWND m_hWndTop;                 // top level parent window (may be disabled)  

55.   

56.         virtual void PreInitDialog();  

57.     HWND PreModal();  

58.     void PostModal();  

59. };  

2.模态对话框的实现
  
Win32 SDK编程下的模态对话框使用了Windows提供给对话框窗口的窗口过程和自己的对话框过程,对话框过程将被窗口过程调用。但在MFC下,所有的窗口类都使用了同一个窗口过程,

CDialog也不例外。CDialog对象在创建Windows对话框时,采用了类似于CWnd的创建函数过程,采用子类化的手段将Windows提供给对话框的窗口过程取代为AfxWndProc或者AfxBaseWndProc

同时提供了对话框过程AfxDlgProc。那么,这些过程是如何实现或者协调的呢?下文将予以分析。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值