首页 > 编程知识 正文

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

时间:2023-05-06 12:19:04 阅读:121379 作者:1921

windows APP应用程序工作的基本流程是接收用户的数据,进行适当的处理,然后将处理结果输出到屏幕、打印机或其他输出设备。 那么,APP应用程序如何从用户那里获取数据,并向用户显示修改后的数据呢? 这包括windows APP应用程式的重要使用者介面—— 对话框

对话框的基本知识一般控件介绍如何创建新的对话框类型“模态”对话框和创建显示模态对话框“非模态”对话框

对话框是一个窗口,不仅可以接收消息,还可以移动、关闭和在客户区域中绘制消息。 对话框也可以被认为是一个大容器,可以在其上放置各种标准控件和扩展控件,从而提供更多程序支持用户输入的方法。 控件介绍控件功能控件类静态文本框(Static Text )显示文本,一般接受输入信息CStatic图像控件) Picture的显式位图、图标、框和元文件支持单行和多行编辑的按钮“Button”响应用户输入,而触发相应事件的按钮“Radio Button”则是两个或多个选项中的一个按钮“CButton”复选框“CButton组框”(Group Box )显示正文和框,并在“CButton列表框”(List Box )中列出几个主要相关控件(出于千种常见目的)。 用户可以从此列表中选择一个或多个CListBox组合框(Combo Box ),分为简单表达式、下拉表达式和下拉表达式CComboBox滚动条(Scroll Bar )。 主要用于从预定义范围的值中快速有效地选择整数值的CScrollBar对话框

有两种类型的对话框:“模态”(Modal )对话框和“非模态”(Modeless )对话框。

模式对话框模态对话框表示显示时,在关闭此模式对话框之前,程序中的其他任务无法继续。 例如,如果在Word中使用“文件”>“打开”菜单命令显示“打开”对话框,然后用鼠标选择另一个菜单或执行其他操作,则会听到该对话框以外的声音。 这是因为“打开”对话框是模态对话框。

模式对话框独占了用户的输入。 当模式对话框打开时,用户只能与该对话框交互,而其他用户界面对象不能接收输入信息。

我们平时面临的大多数对话框都是模态对话框。

如果显示模式对话框非模态对话框,则可以在不关闭该对话框的情况下执行程序中的其他任务。 典型的例子是Windows提供的记事本程序的“搜索”对话框。 此对话框不会独占用户输入,即使在打开“查找”对话框后,也可以与其他用户界面对象进行交互,用户可以在搜索时修改文章。 这样可以大大提高我们的易用性,提高效率。

新建和显示对话框首先在VS2017中新建基于对话框的MFC项目,创建Dialog .项目后进行试运行,得到如下图所示的结果。

要在程序中创建自己的对话框,请插入对话框资源。 具体方法是:视图-其他窗口-资源视图(Ctrl Shift E )

结果如图所示。 VS2017自动将其id设置为IDD_DIALOG1,将其添加到“资源视图”选项卡的" Dialog "项下,并在资源编辑窗口中打开此新对话框资源。

这个新的IDD_DIALOG1对话框有两个按钮:确定取消,IDOK和IDOK的ID来自相应的属性对话框VS2017为这两个按钮提供了默认的消息响应函数OnOK和OnCancel。 这些主要功能是关闭对话框。 因此,在运行程序时,单击任一按钮都可以关闭对话框。 但是,如果单击这两个按钮关闭对话框,则返回的结果值会不同。 程序通常基于该返回值来确定用户单击了哪个按钮,并确定用户的行为,即确定还是取消当前操作。

选择名为IDD_DIALOG1的对话框资源本身,打开其属性对话框,然后将其Caption属性更改为“测试”。 以下,该对话框统称为测试对话框。

在MFC中,资源的操作通常在与资源相关的类中进行。 对话框资源还包含一个名为CDialogEx的基类。 因为CDialogEx类派生自CWnd类,所以它是一个与窗口相关的类,主要用于在屏幕上显示对话框。 由此可知,实际上对话框本身也是窗口接口。

在MFC中,资源操作是在一个类中进行的,因此必须创建与此新对话框资源关联的类。 为此,双击新创建的测试对话框将显示如图所示的对话框。 使用此对话框可以创建与新创建的测试对话框资源关联的类。

我们将类名命名为CTestDlg。 默认情况下, h、 cpp文件名与类名相同。 如下图所示。

单击ok后,该新类将显示在诊断程序的类视图选项卡中。 如你所见,

这个CTestDlg 新类有两个重要成员函数,其中一个就是它的构造函数,其定义代码如下:

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

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

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

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

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

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

模态对话框的创建

首先实现模态对话框的创建。创建模态对话框需要调用CDialog 类的成员函数:DoModal, (如下图所示:)该函数的功能就是创建并显示一个模态对话框,其返回值将作为CDialog类的另一个成员函数:EndDialog 的参数,后者的功能就是关闭模态对话框。

在正式显示模态对话框之前我们先为主窗口的确定按钮添加一个事件,来实现模态对话框的显示。我们双击确定按钮,在DialogDlg.cpp文件看到如下代码:

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

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

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

上述代码中,首先定义一个对话框对象:dlg, 然后利用这个对象调用DoModal函数以产生一个模态对话框。另外,在视类中并不知道这个CTestDlg 对话框是什么样的数据类型,所以还必须在视类的源文件中包含这个CTestDlg类的头文件,结果如下图所示,其中红色箭头所指的那行代码就是需要添加的内容。

然后我们编译运行,首先弹出主界面,如下图所示:

然后点击确定,结果如图所示:

当前只能运行此模态对话框,且停止主窗口的运行,直到模态对话框退出,才允许主窗口运行。

非模态对话框的创建

如果要创建非模态对话框,则需要利用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);}

编译运行,见证奇迹的时刻,如图所示:

然而这中方法又引入了新的问题:我们必须释放pDlg占用的资源,否则会造成内存泄漏! 况且这里pDlg还是一个局部指针变量,当它的生命周期结束时,在程序中就无法再引用它所指向的那块内存了。
解决方法同样有两个:一是在主对话框类的定义中添加私有成员变量,然后在主对话框类的析构函数中调用delete函数释放它指向的内存;二是在主对话框类中重载PostNcDestroy虚函数,释放this指针指向的内存。
我们先用第一种方法具体操作如下:

先在DialogDlg.h文件中加入下面一行代码
添加私有成员变量和析构函数

在按钮事件下编写代码: 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;} 运行结果:

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

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

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。