🔳🔳 绘制线条 、画刷绘图、绘制连续线条、绘制扇形效果的线条
🔳🔳 插入符【文本插入符|图形插入符】、窗口重绘、路径、字符输入【设置字体|字幕变色】
🔳🔳 菜单命令响应函数、菜单命令的路由、基本菜单操作、动态菜单操作、电话本实例
🔳🔳 对话框的创建与显示、动态创建按钮、控件的访问【控件调整|静态文本控件|编辑框控件】、对话框伸缩功能、输入焦点的传递、默认按钮的说明
🔳🔳 修改应用程序窗口的外观【窗口光标|图标|背景】、模拟动画图标、工具栏编程、状态栏编程、进度栏编程、在状态栏上显示鼠标当前位置、启动画面
🔳🔳 设置对话框、颜色对话框、字体对话框、示例对话框、改变对话框和控件的背景及文本颜色、位图显示

文章目录
一、基本知识
对话框就是一个窗口,它不仅可以接收消息,而且可以被移动和关闭,甚至可以在客户区进行绘图。对话框相当于一个容器,在它上面能够放置各种各样的标准控件和扩展控件,使程序支持用户输入的手段更加丰富。
1.1 常用控件介绍
在MFC中,所以的控件类都由CWnd类派生的。因此控件也是窗口。通常控件作为对话框的子窗口而创建的。控件也可以出现在视类窗口、工具栏和状态条中。
MFC的控件类封装类控件的功能。
控件 | 功能 | 对应控件类 |
---|---|---|
静态文本框(Static Text) | 显示文本,一般不接受输入信息 | CStatic |
图像控件(Picture) | 显示位图、图标、方框和图元文件,一般不接受输入信息 | CStatic |
编辑框(Edit Box) | 输入并编辑正文,支持单行和多行编辑 | CEdit |
按钮(Button) | 响应用户的输入,触发相应的事件 | CButton |
复选框(Check Box) | 用于选择标记,可以有选中、未选中和不确定三种状态 | CButton |
单选按钮(Radio Button) | 用于从两个或多个选项中选中一项 | CButton |
组框(Group Box) | 显示正文和方框,主要用于将相关的一些控件(用于共同的目的)组织在一起 | CButton |
列表框(List Box) | 显示一个列表,用户可以从该列表中选中一项或者多项 | CListBox |
组合框(Combo Box) | 是一个编辑框和一个列表框的组合,分成简易式、下拉式和下拉列表式 | CComboBox |
滚动条(Scroll Bar) | 主要用于从一个预定义范围值中迅速而有效地选取一个整数值 | CScrollBar |
1.2 对话框的种类
对话框分为两种:
🔲◼◾ 模态对话框
模态对话框是指当其显示时,程序会暂停执行,直到关闭这个模态对话框后,才能继续执行程序中其他任务。
模态对话框垄断了用户的输入,当一个模态对话框打开时,用户只能与该对话框进行交互。而其他用户界面对象接收不到输入信息。我们平时所遇到的大部分对话框都是模态对话框。
例如:在Word中利用文件的打开菜单命令显示一个 “打开” 对话框后,再用鼠标去选择其他菜单或者进行该对话框以外的任何操作时,只会听到嘟嘟声。这是因为 “打开” 对话框是一个模态对话框。
🔲◼◾ 非模态对话框
当非模态对话框显示时,允许转去执行程序中其他任务,而不用关闭这个对话框。
二、对话框的创建与显示
先创建一个virtual studio类型的单文档应用工程,程序名为Mybole。
点击帮助菜单的子菜单关于Mybole,会出现一个对话框。这是MFC为我们创建的一个“关于”对话框,主要用于显示程序的版本号和版权信息。
自己创建对话框,需要通过插入一个对话框资源。具体步骤:资源视图—>右键Dialog—>添加资源—>新建。
这个新建的IDD_DIALOG1对话框中有两个按钮: OK 和Cancel,并通过它们的属性对话框可以发现它们的ID分别为IDOK和IDCANCEL。VC++已经为这两个按钮提供了默认的消息响应函数OnOK和OnCancel,它们实现的主要功能都是一样的,就是关闭对话框。因此当程序运行时,单击这两个按钮中的任何一个都可以关闭对话框。但是单击这两个按钮关闭对话框后,返回的结果值是不一样的。在程序中通常根据该返回值来判断用户单击的是哪个按钮,从而确定用户的行为:是确定还是取消当前操作。
我们选中IDD_DIALOG1这个对话框资源本身,打开其属性对话框,将其Caption属性设置为:“测试”,以下统称这个对话框为测试对话框。
在MFC中,对资源的操作通常都是通过一个与资源相关的类来完成的。对话框资源也有一个相应的基类: CDialog。CDialog类派生于CWnd类,所以它是一个与窗口相关的类,主要用来在屏幕上显示一个对话框。对话框本身也是一个窗口界面。
在MFC中对资源的操作是通过一个类来完成的,那么就需要创建一个类与这个新建的对话框资源相关联。
① 在新建的对话框上双击鼠标左键,可弹出添加MFC类的界面。
② 对话框 ID项的内容已经被自动填充,就是刚才新建的那个对话框资源标识:IDD_DIALOG1,并且在基类项中也指定了这个新类的基类: CDialogEx。可以更换成CDialog基类。
③ 设置新类名。在输入类名的同时, 头文件和源文件会自动填充。
生成的CTestDialog类的构造函数如下。此类与IDD_DIALOG1相关联。
CTestDialog::CTestDialog(CWnd* pParent /*=nullptr*/)
: CDialog(IDD_DIALOG1, pParent)
{
}
在程序中显示此对话框。
1)先在帮助菜单后添加一个菜单项,打开其属性对话框,将其Caption属性设置为**“对话框”,PopUp设置为False**,并将其ID设置为IDM_DIALOG。
2)为此子菜单添加COMMAND命令消息响应函数。视类CMyboleView捕获对话框菜单项命令响应。
2.1 模态对话框的创建
创建模态对话框需要调用CDialog类的成员函数:DoModal,该函数功能就是创建并显示一个模态对话框。其返回值将作为CDialog类的另一个成员函数:EndDialog的参数,功能是关闭模态对话框。
✨ 1)视类引入CTestDialog的头文件。
🔴1.1)视类源文件文件引入#include "CTestDialog.h
🟡 1.2)后续根据提示进行添加。
✨✨ 2)定义对话框对象,并利用此对象调用DoModal函数以产生一个模态对话框。
void CMyboleView::OnDialog()
{
// TODO: 在此添加命令处理程序代码
CTestDialog dlg;
dlg.DoModal();
}
运行程序,点击对话框菜单,即可弹出自己创建的测试对话框。在此点击菜单中的任意菜单项都不会反应。
📋📋 原因:因为当Mybole程序执行到CMyboleView类OnDialog函数中的DoModal这行代码时,它就会停在这行代码处,不再向下执行。只有这个模态对话框被关闭了之后,这行代码才会返回,程序才能继续执行。
2.2 非模态对话框的创建
创建非模态的对话框,需要利用CDialog类的Create成员函数。该函数具有以下两种形式的声明:
BOOL create(LPCTSTR lpszTemplateName,CWnd* pParentWnd = NULL);
BOOL create(UINT nIDTemplate, CWnd* pParentWnd = NULL);
- 第一个参数:
🔳 是对话框资源的ID(nIDTemplate参数)
🔳 或者是对话框模板的名称(IpszTemplateName参数)。 - 第二个参数指定了对话框的父窗口。
如果其值是NULL,对话框的父窗口就是主应用程序窗口。
在CMyboleView类OnDialog函数中实现创建非模态对话框的功能。
void CMyboleView::OnDialog()
{
// TODO: 在此添加命令处理程序代码
//CTestDialog dlg;
//dlg.DoModal();
CTestDialog dlg;
dlg.Create(IDD_DIALOG1, this);
}
🔳◼◾ 问题一:运行Mybole程序,单击程序菜单栏上的对话框菜单,发现并未出现测试对话框窗口。
📋📋 原因:当利用Create函数创建非模态对话框时,还需要调用ShowWindow函数将这个对话框显示出来。
🟢🟢 解决:在Create函数调用后再调用显示函数ShowWindow函数:
void CMyboleView::OnDialog()
{
// TODO: 在此添加命令处理程序代码
//CTestDialog dlg;
//dlg.DoModal();
CTestDialog dlg;
dlg.Create(IDD_DIALOG1, this);
dlg.ShowWindow(SW_SHOW);
}
📢📢📢 DoModal函数创建对话框时不需要ShowWindow函输。这是因为DoModal函数本身就有显示模态对话框的作用。所以模态对话框不需要再调用ShowWindow函数来显示对话框了。
🔳◼◾ 问题二:运行程序,单击程序菜单栏上的对话框菜单,发现任然出现问题。
📋📋 原因:创建的非模态对话框对象(dlg)是一个局部对象,当程序执行时会依次执行各条代码。当OnDialog函数的右大括号执行结束时,dlg这个对象的生命周期也就结束了,它就会销毁与之相关联的对话框资源。
📢📢📢 为什么上面创建模态对话框时就可以使用局部对象呢?
上面已经讲过,在创建模态对话框时,当执行到调用DoModal函数以显示这个对话框时,程序就会暂停执行。直到模态对话框关闭之后,程序才继续向下执行。也就是说,当模态对话框显示时,程序中创建的dg这个对象的生命周期并未结束。
🟢🟢 解决:在创建非模态对话框时,不能把对话框对象定义为局部对象。对于这个问题,有两种解决办法:
① 把这个对话框对象定义为视类的成员变量
- 先定义dlg为一个视类成员变量:
- 然后修改命令响应函数代码:
⭕ 问题2.1:运行程序,发现编译出错:void CMyboleView::OnDialog() { // TODO: 在此添加命令处理程序代码 //CTestDialog dlg; //dlg.DoModal(); //CTestDialog dlg; dlg.Create(IDD_DIALOG1, this); dlg.ShowWindow(SW_SHOW); }
🟢🟢 解决办法:在视类的头文件中引入CTestDialog的头文件。
② 将对话框对象定义为指针,在堆上分配内存。
📢📢📢 在堆上配的内存,与程序的整个生命周期是一致的(程序中不主动销毁)。
void CMyboleView::OnDialog()
{
// TODO: 在此添加命令处理程序代码
//CTestDialog dlg;
//dlg.DoModal();
CTestDialog* dlg=new CTestDialog;
dlg->Create(IDD_DIALOG1, this);
dlg->ShowWindow(SW_SHOW);
}
⭕问题2.2:定义的dlg这个指针变量是一个局部对象,当它的生命周期结束时,它所保存的内存地址就丢失。那么在程序中也就无法再引用到它所指向的那块内存。
🟢🟢 解决:解决办法有两种:
① 将这个指针变量定义为视类(CMyboleView)的成员变量,然后在CMyboleView类的析构函数中调用delete函数来释放这个指针变量所指向的那块内存;
在构造函数中初始化,在析构函数中释放。
CMyboleView::CMyboleView() noexcept
{
// TODO: 在此处添加构造代码
pDlg = new CTestDialog;
}
CMyboleView::~CMyboleView()
{
if (pDlg != NULL) {
delete pDlg;
pDlg = NULL;
}
}
......
void CMyboleView::OnDialog()
{
// TODO: 在此添加命令处理程序代码
//CTestDialog dlg;
//dlg.DoModal();
//CTestDialog* dlg = new CTestDialog;
//dlg->Create(IDD_DIALOG1, this);
//dlg->ShowWindow(SW_SHOW);
pDlg->Create(IDD_DIALOG1, this);
pDlg->ShowWindow(SW_SHOW);
}
② 在CTestDlg类中重载PostNcDestroy虚函数,释放this指针所指向的内存。
//CMyboleView.cpp
void CMyboleView::OnDialog()
{
// TODO: 在此添加命令处理程序代码
//CTestDialog dlg;
//dlg.DoModal();
CTestDialog* dlg = new CTestDialog;
dlg->Create(IDD_DIALOG1, this);
dlg->ShowWindow(SW_SHOW);
//pDlg->Create(IDD_DIALOG1, this);
//pDlg->ShowWindow(SW_SHOW);
}
//CTestDialog.cpp
void CTestDialog::PostNcDestroy() {
delete this;
CDialog::PostNcDestroy();
}
//CTestDialog.h
protected:
void PostNcDestroy();
2.3 OK按钮
无论创建的是模态对话框,还是非模态对话框,当单击对话框上的OK按钮时,对话框都会消失。但有一点需要注意:
- 对模态对话框而言,此时对话框窗口对象被销毁了。
- 对非模态对话框来说,对话框窗口对象并未被销毁,只是隐藏起来了。
非模态对话框中单击OK按钮后,程序所发生的事情:
1. 程序调用基类(CDialog)的OnOK函数,这是一个虚函数。
2. OnOK调用EndDialog函数,这个函数用于终止模态对话框,而对于非模态对话框,这个函数只是使对话框窗口不可见,并不销毁它。所以对于非模态对话框来说,如果有一个ID值为IDOK的按钮,就必须重写基类的OnOK这个虚函数,并在重写的函数中调用DestroyWindow函数,以完成销毁对话框的工作,同时注意不要再调用基类的OnOK函数。同样,如果非模态对话框中有一个ID值为IDCANCEL的按钮,也必须重写基类的OnCancel虚函数,并在重写的函数中调用DestroyWindow函数销毁对话框,同时注意不要再调用基类的OnCancel函数。
三、动态创建按钮
利用模态对话框实现一个功能:
点击对话框中某个按钮,就在对话框中动态创建一个新按钮。
注释与非模态对话框有关的代码(一定要屏蔽掉CTestDlg类中重载的PostNcDestroy虚函数,否则程序运行会出现debug assertion failed错误)。恢复与模态框有关的代码。
✨ 1)为IDD_DIALOG1对话框添加一个按钮。
鼠标点击资源视图–>Dialog–>点击IDD_DIALOG1这个对话框资源ID,会打开对应的对话框资源。点击工具箱,会看到许多资源,将Button按钮拖动到对话框中。
将添加的按钮的ID设置为IDC_BIN_ADD,Caption设置为:Add。
✨✨ 2)响应Add按钮单击消息。为程序添加Add按钮点击消息的响应函数。
鼠标右键单击Add,选择类向导。因为现在是对CTestDialog对话框进