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); }
- 先在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; } - 运行结果:

至此,我们的模态对话框和非模态对话框就创建完成了!!
如果这篇文章对你的学习起到一定的帮助,记得点个赞哦!!
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/202862.html原文链接:https://javaforall.net
