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

文章目录
一、基于对话框的程序
新建一个基于对话框的项目,项目名称:DlgTest。
生成的项目结构为:
解决方案结构:
类视图下有三个类:
- CAboutDlg
派生于CDialog类,这个类与SDI应用程序中相应的类:CAboutDlg作用相同,用于显示一个关于对话框。 - CDlgTestApp
这是MFC应用程序中必不可少的一个类,派生于CWinApp类,它的对象代表了应用程序本身。 - CDlgTestDlg
派生于CDialog类,基于对话框的MFC应用程序的主界面。
基于对话框的应用程序中没有从CView类派生出来的视类,也没有从CFrameWnd类派生出来的框架类,以及从CDocument类派生的文档类,它只有从CDialog派生出来的一个对话框类:CTestDlg,这类应用程序的窗口就是一个对话框界面。
资源视图:
运行该程序生成的界面:
二、“逃跑”的按钮
实现功能:
DlgTest程序的对话框主界面上增加一个按钮,当用鼠标单击这个按钮时,该按钮会自动移动到另一个位置,就像一个“逃跑”的按钮。
✨ 1)首先删除MFC AppWizard自动创建的对话框资源: IDD_DLGTEST_DIALOG上的所有控件。
✨✨2)然后添加一个按钮控件,利用其属性对话框,将其Caption修改为:你能抓住我吗? 。
打开IDD_DLGTEST_DIALOG对话框的属性对话框,可以看到在其字体选项卡上,有一个Font按钮:
✨✨✨3)为了实现这种“逃跑”按钮,可以通过捕获鼠标移动的消息,并在此消息响应函数中让这个按钮的位置发生移动来实现。
介绍一种巧妙的实现方法:在IDD_DLGTEST_DIALOG对话框资源窗口中,复制刚才添加的那个按钮,并在其下方进行粘贴操作,这样IDD_DLGTEST_DIALOG对话框资源中就有了两个外观相同的按钮。在程序实现时,首先让其中的一个按钮隐藏,另一个按钮显示;当随后把鼠标移动到显示的按钮上时,将该按钮隐藏,把另一个显示出来。因为这两个按钮的外观是完全一样的,因此这样的效果给用户的感觉好像按钮是自动跑到新位置处的。
🔵🔵 3.1)在IDD_DLGTEST_DIALOG对话框资源窗口中,复制刚才添加的那个按钮。
为了实现上述所述功能,程序首先就要捕获鼠标移动消息,那么由谁来捕获这个消息比较合适呢?
如果让对话框窗口(CDlgTestDlg类)来捕获,一旦鼠标在对话框窗口中秘动,程序就会让按钮上下移动,这当然不是想实现的功能。想要的功能是当鼠标移动到按钮上时,按钮才上下移动。鼠标移动的消息应该由按钮窗口来捕获。所以在MFC应用程序中,可以创建一个从CButton类派生的新类,然后将按钮控件上这种新类型的成员变量相关联,从而就把按钮控件与一个自定义的按钮窗口类关联起来。
🟢🟢 3.2)为应用程序增加一个从CButton派生的新类,设置新类的名称(Name)为: CNewButton,基类为: CButton。
接下来把对话框中的两个按钮分别关联一个成员变量,关联的变量类型为CNewButton类型,即将变量的类型设置为上面添加的新类。两个Button按钮的ID分别为:
- IDC_BUTTON1,设置变量名称为: m_btn1。
- IDC_BUTTON2,设置变量名称为: m_btn2。
发现DlgTestDlg中有两处代码变化:
-
第一处:头文件DlgTestDlg.h中生成代码:
发现CNewButton处飘红,是由于为对话框的一个子控件关联了一个成员变量,而这个成员变量的类型是CNewButton类,这个类是刚刚创建的新类。如果在CDlgTestDlg类中想要识别这种类型的话,就必须在CDlgTestDlg类中包含这个新类的头文件。点击飘红的CNewButton类,会给出解决方案。点击给出解决方案就可解决问题。
在CNewButton源文件中添加头文件#include "pch.h"
,否则会报错:错误C1010:在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include “pch.h””? -
第二处:源文件DlgTestDlg.cpp中生成代码:
void CDlgTestDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_BUTTON1, m_btn1); DDX_Control(pDX, IDC_BUTTON2, m_btn2); }
🟣🟣3.3)CNewButton类捕获鼠标移动消息。
打开类视图的选项卡,在CNewButton上单击鼠标右键,点击属性,在消息列表中找WM_MOUSEMOVE。点击 OnMouseMove按钮。
CNewButton的源文件的中BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏之间即添加了消息响应函数,并添加了消息响应函数的实现:
#include "CNewButton.h"
BEGIN_MESSAGE_MAP(CNewButton, CButton)
ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()
void CNewButton::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CButton::OnMouseMove(nFlags, point);
}
🟡🟡3.4)实现按钮的隐藏功能。因为当鼠标移动到该按钮上时,就会由这个按钮的鼠标移动消息的响应函数 OnMouseMove来响应,在此函数中以SW_HIDE参数去调用这个按钮的ShowWindow函数,即可将其隐藏。
这时为了让另一个按钮显示出来,必须要知道另一个按钮所关联的那个对象的内存地址,然后才能调用该对象的ShowWindow函数,将其显示出来。
为了在一个按钮对象中获取另一个按钮控件对象的地址,最简单的方式就是在CNewButton类中定义一个成员变量,让其指向另一个按钮对象的地址。
💦💦💦 3.4.1)因此为CNewButton类再添加一个公开的CNewButton* 类型的成员变量: m_pBtn。
当用CNewButton类去实例化CDlgTestDlg类的成员变量 m_btn1和m_btn2时,这两个对象内部就都有了一个 m_pBtn成员变量,让这两个对象内部的 m_pBtn变量分别保存对方的首地址,相当于这两个对象互相交换了自己的首地址。于是当m_btn1按钮隐藏时,就可以利用它的成员变量 m_pBtn去调用ShowWinolw函数,将m_btn2按钮显示出来;同样地,当m_btn2按钮隐藏时,可以利用它的成员变量 m_pBtn去调用ShowWindow函数,将m_btn1按钮显示出来。
💦💦💦 3.4.2)在CDlgTestDlg类中把m_btn1和m_btn2这两个对象的首地址交换一下,这一工作可以放在OnInitDialog函数中实现。根据前面的知识,OnInitDialog函数就是 WM_INITDIALOG消息的响应函数,该消息是在对话框要显示之前发送的。在CDlgTestDlg类的OnInitDialog函数的最后,但要在return语句之前添加:
m_btn1.m_pBtn = &m_btn2;
m btn2.m_pBtn = &m_btnl;
💦💦💦 3.4.3)然后在CNewButton类的OnMouseMove函数中,先让对象自己隐藏起来,然后调用成员m_pBtn的ShowWindow函数将对方显示出来:
void CNewButton::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//隐藏鼠标处的窗口
ShowWindow(SW_HIDE);
//显示m_pBtn所指向的窗口
m_pBtn->ShowWindow(SW_SHOW);
CButton::OnMouseMove(nFlags, point);
}
当鼠标移动到第一个按钮对象(m_btn1)上时,程序就会调用该对象的OnMouseMove函数。在这个函数中,首先调用ShowWindow函数将自身隐藏。因为第一个按钮对象的成员m_pBtn保存的是第二个按钮对象m_btn2的地址,所以接下来的m_pBtn->ShowWindow (SW_SHOW)的调用就将第二个按钮显示了出来。当随后鼠标移动到第二个按钮对象上时,实现原理相同,是对m_bnt2对象来说,它的m_pBtn成员变量保存的是m_btn1按钮的地址。
但是这个程序还有一个缺陷:初始显示时,两个按钮都是显示状态,这很容易让用户看出程序的实现方式。
📋📋 解决:在初始时应该隐藏一个按钮。利用按钮属性对话框,把第一个按钮的Visible属性去掉。这时只有一个按钮处于显示状态,然后把鼠标移到这个按钮上,这个按钮就隐藏了,并显示出另一个按钮。再把鼠标移到这个显示的按钮上时,它又消失了,另一个又显示出来。
✨✨✨✨ 4)利用SetWindowPos函数来设置按钮在屏幕上移动的新位置
三、属性表单和向导的创建
点击VS的开发窗口中菜单项中的工具菜单命令,在选择此菜单项下的子菜单选项。打开的对话框就是一个属性表单,它的每一个选项卡就是一个属性页。一个属性表单由一个或多个属性页组成。它有效解决了大量信息无法在一个对话框上显示的问题,并提供了对信息的分类和组织管理功能。在程序设计中,可以将相关的选项放到一个属性页中。
现在重新建一个叫Prop的应用程序。项目样式:MFC standard、应用程序类型:单个文档。
生成的界面:
3.1 创建属性页
为了创建属性表单,首先需要创建属性页,MFC中属性页对应的类是CPropertyPage,该类生成的对象代表了属性表单中一个单独的属性页。该类的继承层次结构:
可以看出,CPropertyPage类是从CDialog派生而来的。因此,一个属性页窗口其实就是一个对话框窗口。
✨ 1)创建一个对话框窗口,首先需要创建对话框资源。点击 资源视图 –>右键Dialog–> 添加资源–> 资源视图 ,在弹出的资源类型对话框中点击Dialog菜单项左侧的 +,即可看到三种属性页资源:
- IDD_PROPPAGE_LARGE、
- IDD_PROPPAGE_MEDIUM、
- IDD_PROPPAGE_SMALL。
创建3个IDD_PROPPAGE_LARGE类型的属性页资源。
修改3个属性页资源的ID与标题:
- 第一个:IDD_PROP1+Page1
- 第二个:IDD_PROP2+Page2
- 第三个:IDD_PROP3+Page3
属性页资源和通常插入的对话框资源之间的区别:
1. 对比外观选项卡属性:
可以看出,二者区别:
2. 对比其他属性:
📢📢📢 知道了这两种资源之间的区别后,可以在程序中先增加一个普通对话框资源,然后修改其属性,使其符合属性页资源的要求,然后把它当作属性页资源来使用。
✨✨ 2)首先删除Prop程序中各个属性页资源上已有的静态文本控件,然后在每一个属性页中增加一些控件。
-
在第一个属性页:
1) 放置一个组框(Group Box)。组框可以用来起一个分组的作用,可以把相关的一些选项放置在一个组框中。
将新添加的这个组框的标题修改为:请选择你的职业。
1.1)然后在这个组框内放置三个单选按钮( Radio Button)。更改属性名依次为:程序员、老师、老板。
2)再放置一个列表框控件(List Box),这种类型的控件提供了信息的一种简单的组织方式,可以排列一些字符串提供给用户进行选择。
2.1)在该列表框上放置一个静态文本控件(Static Text),这种控件主要起标示作用。
将其文本属性修改为:请选择你的工作地点。
最后应该调整一下各个控件的Caption,以及相对位置,使其美观些。
-
在第二个属性页:
1)首先放置一个组框(Group Box)。
将其标题修改为: 请选择你的兴趣爱好。
2)组框内添加四个复选框(Check Box)。
把它们的标题分别修改为:“足球”、“篮球”、“排球”、“游泳”。
-
在第三个属性页:
1)首先增加一个组合框(Combo Box)。
增加组合框时应注意:拖放时要将它的范围拉得大些,否则在程序运行时单击它右边的下拉箭头时,显示的下拉空间很小。无法将其下拉框中的内容显示出来。
Type选择Drop List类型。调整该组合框下拉列表部分的范围,方法是在对话框资源处于编辑状态时,把鼠标移动到该组合框控件右边向下的箭头上,当鼠标变成双向箭头形状时,按下鼠标左键,把组合框的下拉列表范围拖动到合适大小。
组合框提供了编辑框加列表框的功能。VC++提供了三种类型的组合框,打开组合框控件的属性对话框,并单击Type选项页:
🔳 简易式(Simple)
这种类型的组合框包含一个编辑框和一个总是显示的列表
🔳下拉式(Dropdown)
类似于简易式组合框,二者的区别在于下拉式组合框仅当单击下拉箭头后,列表框才会弹出。
🔳下拉列表式(Drop List)
下拉列表式组合框也有一个下拉的列表框,但它的编辑框是只读的,不能输入字符。也就是说,这种类型的组合框只能从其下拉列表中选择内容。2)在第三个属性页上,在添加的组合框控件上方摆放一个静态文本,其标题设置为: 请选择你的薪资水平。
✨✨✨ 3)为属性页对话框资源添加3个属性页类。
设定新类的名称分别为CProp1、CProp2、CProp3,并把它的基类选择为: CPropertyPage。
根据下面的方法添加三个新类:解决用类向导添加MFC类,基类列表没有CPropertyPage类。
在实际编程过程中,有时利用上述方法添加新类后,可能会出现这样的现象:系统会提示无法打开新类的源文件和头文件。这是VC++自身的问题。实际上,这时程序已经完成了新类的添加,只不过这个类的信息没有记录在类向导中。在类向导对话框的类名下拉列表中找不到这个新添加的类名,但这个类确实是一个完整的类,它有源文件和头文件。为了解决这个问题,即如何让类向导找到新添加的类,可以按以下步骤:
① 保存工程。
② 利用文件中的关闭解决方案关闭当前工作区。
③ 在Windows资源浏览器中找到该工程所在的目录,并找到.clw文件,该文件存储的就是类向导的一些相关信息。
④ 回到VC++开发环境,打开刚刚关闭的工程,打开类向导。会弹出一个话话框,该对话框提示类向导的数据库(即.clw文件) 不存在,询问用户是否愿意从工程的源文件中创建这个数据库。
⑤ 单击【是】按钮,就会弹出一个对话框,通常不需要对此对话框进行任何修改,直接单击【OK】按钮即可,完成.clw文件的创建。这时,就会发现在类向导对话框的类名下拉列表中就可以看到先前添加的新类了。
3.2 创建属性表单
为了创建一个属性表单,首先需要创建一个CPropertySheet对象,接下来,在此对象中为每一个属性页创建一个对象(CPropertyPage类型),并调用AddPage函数添加每一个属性页,然后调用DoModal函数显示一个模态属性表单,或者调用Create函数创建一个非模态属性表单。
因此,可以通过以下几个步骤实现属性表单创建的功能:
✨1)为Prop程序创建一个属性表单对象。
通过类向导添加MFC类,新类命名为:CPropSheet,