Windows对话框分为两类:

模态对话框
非模态对话框

  • 模态对话框: 当模态对话框弹出后,本应用程序其他窗口将不再接受用户输入,只有该对话框响应用户输入,在对它进行相应的操作退出后,其他窗口才能继续与用户交互。
  • 非模态对话框: 当非模态对话框弹出后,本程序其他窗口仍能响应用户输入;非模态对话框一般用来显示提示信息等。 

当使用Visual Studio创建项目默认状态下,弹出的对话框其实就是属于模态的对话框,具体代码看下创建的项目中的InitInstance方法,如下:

CMFCDemosDlg dlg; //定义对话框CMFCDemosDlg对象
m_pMainWnd = &dlg; //设置主对话框为demodlg
INT_PTR nResponse = dlg.DoModal(); //弹出对话框,并将doModal()的返回值(退出按钮的id)赋值给nResponse
if (nResponse == IDOK)  //点击确定按钮操作
{
    // TODO: 在此放置处理何时用
    //  “确定”来关闭对话框的代码
}
else if (nResponse == IDCANCEL) //点击取消按钮的操作
{
    // TODO: 在此放置处理何时用
    //  “取消”来关闭对话框的代码
}
else if (nResponse == -1) //如果函数不能创建对话框,则返回-1
{
    TRACE(traceAppMsg, 0, "警告: 对话框创建失败,应用程序将意外终止。\n");
    TRACE(traceAppMsg, 0, "警告: 如果您在对话框上使用 MFC 控件,则无法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");
}

弹出对话框比较关键的一个函数,就是对话框类的DoModal()函数。CDialog::DoModal()函数的原型为:

virtual INT_PTR DoModal();

此函数返回值为整数值,指定了传递给CDialog::EndDialog(该函数用于关闭对话框)的nResult参数值。如果函数不能创建对话框,则返回-1;如果出现其它错误,则返回IDABORT。调用了它对话框就会弹出,返回值是退出对话框时所点的按钮的ID,比如,我们点了“退出”按钮,那么DoModal返回值为IDCANCEL.

下面我们模仿这里的代码来实现一个模态对话框:

1.这是我的工程中创建项目自带的对话框,在其中增加两个控件,Edit Control和Button各一个,双击对话框中的Button,系统会自动创建按钮点击 (OnBnClickedButton1)的方法,留着备用:

2.创建一个新的资源文件,名字默认即可:IDD_DIALOG1,随意调整下里面的控件:

3.右键点击对话框,添加类,类名随意,这里我的类名叫CTipDlg;

4.创建完毕后,回到第一个对话框的.cpp文件中,先#include "CTipDlg.h",然后找到OnBnClickedButton1方法,写入以下代码:

void CMFCDemosDlg::OnBnClickedButton1(){
// TODO: 在此添加控件通知处理程序代码
//弹出提示对话框
INT_PTR nRes;             // 用于保存DoModal函数的返回值   
CTipDlg tipDlg;           // 构造对话框类CTipDlg的实例   
nRes = tipDlg.DoModal();  // 弹出对话框 
}

5.Ctrl+F5运行程序,点击对话框中的按钮,结果如下:

此时屏幕上有两个对话框,移动上层的对话框,尝试点击下层对话框中的EditControl会发现此时的EditControl无法获取焦点,也就无法输入了,此种情况就是模态对话框.


 

再来实现一个非模态对话框:

实际上,模态对话框和非模态对话框在创建对话框资源和生成对话框类上是没有区别的,所以项目中已经创建的资源与对话框的类文件都不需要更改,我们需要做的如下:

1.此前CTipDlg的头文件包含在系统创建的.cpp文件中,我们修改到在.h文件中,然后在.h文件中创建CTipDlg的指针变量:

private: CTipDlg * m_pTipDlg;

2.找到系统创建的对话框cpp中的构造函数,并在里面输入

CMFCDemosDlg::CMFCDemosDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_MFCDEMOS_DIALOG, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    m_pTipDlg = NULL; //在构造函数体中添加m_pTipDlg = >NULL;,这是个好习惯,在任何指针变量使用前都初始化,可以避免因误访问重要内存地址而破坏此地址的数据。
}

3.修改按钮点击里的代码,改为非模态对话框创建方法:

void CMFCDemosDlg::OnBnClickedButton1(){
// TODO: 在此添加控件通知处理程序代码
//弹出提示对话框   
if (NULL == m_pTipDlg)
  { //如果为空,则创建对话框实例
       m_pTipDlg = new CTipDlg();
       m_pTipDlg->Create(IDD_DIALOG1, this);
  }
    m_pTipDlg->ShowWindow(SW_SHOW); // 显示非模态对话框 
}

4.运行程序,点击"点哥跳转新Dlg",跳转新对话框后,拖开新对话框,发现下层的对话框的EditControl是可以获取焦点并进行输入的,这就是非模态对话框.