一文搞懂如何创建基于对话框的模态对话框和非模态对话框

一文搞懂如何创建基于对话框的模态对话框和非模态对话框Windows 应用程序工作的基本流程是从用户那里得到数据 经过相应的处理之后 再把处理结果输出到屏幕 打印机或者其他的输出设备上 那么 应用程序是如何从用户那里得到数据 并且再将修改后的数据显示给用户的呢 这就需要用到 Windows 应用程序中一个很重要的用户接口 对话框 对话框基本认识常用控件介绍对话框的种类模态对话框非模态对话框对话框的新建和显示模态对话框的创建非模态对话框的创建对话框

Windows应用程序工作的基本流程是从用户那里得到数据,经过相应的处理之后,再把处理结果输出到屏幕、打印机或者其他的输出设备上。那么,应用程序是如何从用户那里得到数据,并且再将修改后的数据显示给用户的呢?这就需要用到 Windows应用程序中一个很重要的用户接口 ——对话框


对话框其实就是一个窗口,不仅可以接收消息,而且还可以被移动和关闭,甚至可以在它的客户区中进行绘图。我们也可以将对话框看成是一个大容器,在它上面能够放置各种各样的标准控件和扩展控件,使程序支持用户输入的手段更加丰富。

常用控件介绍

控件 功能 控件类
静态文本框(Static Text) 显示文本, 一般不能接受输入信息 CStatic
图像控件(Picture) 显式位图、 图标、 方框和图元文件, 一般不能接受输入信息 CStatic
编辑框(Edit Box) 输入并编辑正文,支持单行和多行编辑 CEdit
按钮(Button) 响应用户的输入,触发相应的事件 CButton
单选按钮(Radio Button) 用来从两个或多个选项中选中一项 CButton
复选框(Check Box) 用作选择标记,可以有选中、未选中和不确定三种状态 CButton
组框(Group Box) 显示正文和方框,主要用来将相关的一些控件(用千共同的目的)组织 在一起 CButton
列表框(List Box) 显示一个列表,用户可以从该列表中选择一项或多项 CListBox
组合框(Combo Box) 是一个编辑框和一个列表框的组合。分为简易式、下拉式和下拉列表式 CComboBox
滚动条(Scroll Bar) 主要用来从一个预定义范围值中迅速而有效地选取一个整数值 CScrollBar

对话框的种类

对话框分为两类: 模态(Modal)对话框和非模态(Modeless)对话框。

模态对话框

模态对话框是指当其显示时,程序会暂停执行,直到关闭这个模态对话框后,才能继续执行程序中其他任务。例如, 在Word中利用【文件/打开】菜单命令显示一个 “打开 ”对话框后,再用鼠标去选择其他菜单,或者进行该对话框以外的任何操作时,就会听到那个声音(大家都懂),这是因为 “打开 “ 对话框是一个模态对话框。
模态对话框垄断了用户的输入,当一个模态对话框打开时,用户只能与该对话框进行交互,而其他用户界面对象接收不到输入信息。
我们平时所遇到的大部分对话框都是模态对话框。




非模态对话框

非模态对话框显示时,允许转而执行程序中其他任务,而不用关闭这个对话框。 典型的例子是Windows提供的记事本程序中的 “查找”对话框,该对话框不会垄断用户的输入,打开“查找”对话框后,仍可以与其他用户界面对象进行交互,用户可以一边查找,一边修改文章,这样,就大大方便了我们的使用,提高了效率。

对话框的新建和显示

CTestDlg::CTestDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_DIALOG1, pParent) { 
     } 

可以看到,CTestDlg 类的构造函数首先调用其基类:CDialogEx的构造函数,并传递两个参数:一个是CTestDlg 类的IDD成员,一个是父窗口指针。打开 CTestDlg 类的头文件,就可以发现这个 IDD 就是这个对话框资源的ID, 代码如下:

// 对话框数据 #ifdef AFX_DESIGN_TIME enum { 
     IDD = IDD_DIALOG1 }; #endif 

CTestDlg 类的另一个函数是:DoDataExchange, 主要用来完成对话框数据的交换和校验,其定义代码如下所示:

void CTestDlg::DoDataExchange(CDataExchange* pDX) { 
     CDialogEx::DoDataExchange(pDX); } 

现在,我们就有了一个类 (CTestDlg) 与IDD_DIALOG1这个对话框资源相关联了,就像程序中 CAboutDlg 类与lDD_ABOUTBOX 这个对话框资源相关联一样。接下来,我们希望在程序中显示这个对话框窗口,为此,可以为Dialog程序主界面下的确定按钮添加一个事件,当用户单击这个按钮时就显示这个测试对话框窗口。接下来如何显示这个测试对话框就要看看我们自己的设置了,是模态对话框还是非模态呢?如何实现呢?我们一一进行展示。

模态对话框的创建

void CDialogDlg::OnBnClickedOk() { 
     // TODO: 在此添加控件通知处理程序代码 CDialogEx::OnOK(); } 

我们在这个按钮触发事件下添加代码,实现显示模态对话框,代码如下:

void CDialogDlg::OnBnClickedOk() { 
     // TODO: 在此添加控件通知处理程序代码 CDialogEx::OnOK(); CTestDlg dlg; dlg.DoModal(); } 

非模态对话框的创建

如果要创建非模态对话框,则需要利用CDialog类的Create成员函数。该函数具有以下两种形式的声明:

virtual BOOL Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL); virtual BOOL Create(UINT nIDTemplate, CWnd* pParentWnd = NULL); 

也就是说,Create函数的第一个参数可以是对话框资源的ID(nIDTemplate参数,或者也可以是对话框模板的名称(lps zTemplateName参数)。这个函数的第二个参数指定了对话框的父窗口,如果其值是NULL,对话框的父窗口就是主应用程序窗口。对本例来说,如果这个父窗口参数值是NULL, 对话框的父窗口就是Dialog窗口。这里,我们仍在主窗口的确定按钮事件下实现创建非模态对话框的功能,则首先需要将上面创建模态对话框的代码注释起来,然后在其后面添加创建非模态对话框的代码,结果如下:

void CDialogDlg::OnBnClickedOk() { 
     // TODO: 在此添加控件通知处理程序代码 CDialogEx::OnOK(); /*CTestDlg dlg; dlg.DoModal();*/ CTestDlg dlg; dlg.Create(IDD_DIALOG1,this); } 

编译运行程序, 单击确定,发现并未出现测试对话框窗口。这里,我们一定要注意,当利用Create函数创建非模态对话框时,还需要调用ShowWindow函数将这个对话框显示出来。那为什么上面利用DoModal函数创建对话框时不需要呢?这是因为DoModal函数本身就有显示模态对话框的作用,所以对模态对话框来说,不需要再调用 ShowWindow函数来显示对话框了,但非模态对话框需要调用此函数。因此,我们在上述所示代码的最后再加上下而这行代码:

dlg.ShowWindow(SW_SHOW); 

编译并运行程序,单击确定,发现仍没有出现测试对话框。噫~~问题出在哪里了呢?我们回头看看上面的代码,发现这里创建的非模态对话框对象 dlg 是一个局部对象,当程序执行时,会依次执行各条代码,当OnBnClickedOk函数执行结束时,dlg这个对象的生命周期也就结束了,它就会销毁与之相关联的对话框资源。那为什么上面创建模态对话框时就可以使用局部对象呢?上面也已经说过了,在创建模态对话框时,当执行到调用 DoModal函数以显示这个对话框时,程序就会暂停执行,直到模态对话框关闭之后,程序才继续向下执行。也就是说,当模态对话框显示时,程序中创建的dlg这个对象的生命周期并未结束。因此,在创建非模态对话框时,不能把对话框对象定义为局部对象。查阅资料发现对于这个问题,有两种解决办法:一是把这个对话框对象定义为视类的成员变量; 另一种方式是将它定义为指针,在堆上分配内存。 因为,在堆上分配的内存,与程序的整个生命周期是一致的,当然这里是指程序中不主动销毁的情况。那我们就试一下吧(不理解的就去查阅一下资料,我也是查了大量资料才知道的)
这里,我们采用后一种方式,修改已有代码,结果如下代码所示:

 void CDialogDlg::OnBnClickedOk() { 
     // TODO: 在此添加控件通知处理程序代码 //CDialogEx::OnOK(); /*CTestDlg dlg; dlg.DoModal();*/ /*CTestDlg dlg; dlg.Create(IDD_DIALOG1,this); dlg.ShowWindow(SW_SHOW);*/ CTestDlg *pDlg = new CTestDlg; pDlg->Create(IDD_DIALOG1, this); pDlg->ShowWindow(SW_SHOW); } 
  1. 先在DialogDlg.h文件中加入下面一行代码
    在这里插入图片描述

  2. 添加私有成员变量和析构函数
    在这里插入图片描述
    在这里插入图片描述




  3. 在按钮事件下编写代码:
void CDialogDlg::OnBnClickedOk() {      // TODO: 在此添加控件通知处理程序代码 //CDialogEx::OnOK(); /*CTestDlg dlg; dlg.DoModal();*/ /*CTestDlg dlg; dlg.Create(IDD_DIALOG1,this); dlg.ShowWindow(SW_SHOW);*/ //CTestDlg *pDlg = new CTestDlg; if (NULL == pDlg) {      pDlg = new CTestDlg(); pDlg->Create(IDD_DIALOG1); } pDlg->ShowWindow(SW_SHOW); } CDialogDlg::~CDialogDlg() {      if (NULL != pDlg) {      delete pDlg; } } 
  • 运行结果:
    在这里插入图片描述

我们再用第二种方法释放内存,具体操作如下:

  • 先将第一种方法的代码注释掉,如下图所示:
    在这里插入图片描述
    在这里插入图片描述




  • 为主对话框重载PostNcDestroy虚函数
    在这里插入图片描述

  • 编写代码:
void CDialogDlg::OnBnClickedOk() {      // TODO: 在此添加控件通知处理程序代码 //CDialogEx::OnOK(); /*CTestDlg dlg; dlg.DoModal();*/ /*CTestDlg dlg; dlg.Create(IDD_DIALOG1,this); dlg.ShowWindow(SW_SHOW);*/ //CTestDlg *pDlg = new CTestDlg; if (NULL == pDlg) {      pDlg = new CTestDlg(); pDlg->Create(IDD_DIALOG1); } pDlg->ShowWindow(SW_SHOW); } void CDialogDlg::PostNcDestroy() {      // TODO: 在此添加专用代码和/或调用基类 CDialogEx::PostNcDestroy(); delete pDlg; } 
  • 运行结果:
    在这里插入图片描述

至此,我们的模态对话框和非模态对话框就创建完成了!!

如果这篇文章对你的学习起到一定的帮助,记得点个赞哦!!


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/202862.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午11:07
下一篇 2026年3月19日 下午11:08


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号