Windows学习笔记-10(初步使用MFC)
一、创建MFC项目的基本步骤
1、#include
2、创建一个类继承自 CWinApp
3、重写Initlnstance的虚函数
4、全局范围内定义一个唯一的CWinApp子类对象。
二、操作示例
1、先创建一个空项目,在资源文件处添加一个Dialog对话框,右键添加MFC类:



2、然后添加一个源文件,编写CWinApp派生类和创建其对象:
// 引入MFC核心头文件,提供MFC应用程序所需的基本类(如CWinApp、CWinThread等)
#include
// 引入自定义对话框类CMainDlg的头文件,该对话框将作为应用程序的主窗口
#include "CMainDlg.h"
// 定义应用程序类,继承自MFC的CWinApp类
// CWinApp是MFC应用程序的基类,每个MFC应用程序都必须有一个派生自CWinApp的类
class myApp : public CWinApp
{
public:
// 重写InitInstance函数,这是MFC应用程序的入口点
// 当应用程序启动时,MFC框架会自动调用此函数
BOOL InitInstance() override
{
// 调用基类的InitInstance,执行MFC框架所需的初始化
CWinApp::InitInstance();
// 创建主对话框对象(CMainDlg类的实例)
// CMainDlg是自定义的对话框类,通常通过资源编辑器创建对话框模板
CMainDlg mainDlg;
// 将主对话框设置为应用程序的主窗口
// m_pMainWnd是CWinApp的成员变量,指向应用程序的主窗口
m_pMainWnd = &mainDlg;
//也可使用new在堆上创建对象
//CMainDlg* pMainDlg = new CMainDlg;
//m_pMainWnd = pMainDlg;
// 以模态方式显示主对话框
// DoModal()会显示对话框并进入消息循环,直到对话框关闭
// 在此期间,用户可以与对话框进行交互
mainDlg.DoModal();
// 返回TRUE表示初始化成功,应用程序可以继续运行
// 如果返回FALSE,MFC框架会自动终止应用程序
return TRUE;
}
};
// 创建全局应用程序对象theApp
// MFC要求必须有一个全局的CWinApp派生类对象
// 当程序启动时,MFC框架会自动识别该对象并调用其InitInstance函数
myApp theApp;

无注释代码:
#include
#include"CMainDlg.h" //引入创建对话框的MFC类
class myApp : public CWinApp
{
public:
BOOL InitInstance() override
{
CWinApp::InitInstance();
CMainDlg mainDlg;
m_pMainWnd = &mainDlg;
mainDlg.DoModal();
return TRUE;
}
};
myApp theApp;
关键点说明:
-
MFC应用程序结构:
-
每个MFC应用程序必须有一个
CWinApp派生类 -
必须重写
InitInstance()函数,这是应用程序的入口点 -
需要定义一个全局的应用程序对象
-
-
程序执行流程:
-
程序启动,MFC框架初始化
-
框架自动调用
theApp.InitInstance() -
在
InitInstance()中创建并显示主对话框 -
用户与对话框交互,直到关闭对话框
-
DoModal()返回,InitInstance()返回TRUE -
应用程序继续运行(虽然主窗口已关闭,但进程仍在)
-
-
注意事项:
-
这段代码创建的是模态对话框,对话框关闭后应用程序也会退出
-
如果要创建非模态对话框,需要使用
Create()和ShowWindow()方法 -
MFC应用程序通常使用资源文件(.rc)定义对话框布局
-
CMainDlg类需要在CMainDlg.h中定义,并继承自CDialog或CDialogEx
-
3、设置需要的组件,指定同一组控件的第一个控件(将其组设置为true,比如这里的第一个Radio和第一个CheckBox):

4、右键组件,添加事件处理程序
这里给两个按钮添加单击事件处理程序

为了获取控件的状态,可以给其添加控件变量(这里给第一个Radio和三个checkbox都选择类型为值,第四个checkbox选择为控件类型,为了演示使用的不同):

按住Ctrl + D键可查看Tab键对应的顺序,该顺序和组的第一个控件决定分组,点击可进行修改:


5、实现事件处理程序
// CMainDlg.cpp: 实现文件
//
#include "afxdialogex.h"
#include "CMainDlg.h"
#include "resource.h"
// CMainDlg 对话框
IMPLEMENT_DYNAMIC(CMainDlg, CDialogEx)
CMainDlg::CMainDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_DIALOG1, pParent)
, radio1(FALSE)
, m_check1(FALSE)
, m_check2(FALSE)
, m_check3(FALSE)
{
}
CMainDlg::~CMainDlg()
{
}
void CMainDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Radio(pDX, IDC_RADIO1, radio1);
DDX_Check(pDX, IDC_CHECK1, m_check1);
DDX_Check(pDX, IDC_CHECK2, m_check2);
DDX_Check(pDX, IDC_CHECK3, m_check3);
DDX_Control(pDX, IDC_CHECK4, m_check4);
}
BEGIN_MESSAGE_MAP(CMainDlg, CDialogEx)
ON_BN_CLICKED(IDC_BUTTON1, &CMainDlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &CMainDlg::OnBnClickedButton2)
END_MESSAGE_MAP()
// CMainDlg 消息处理程序
void CMainDlg::OnBnClickedButton1()
{
CString strbuff;
UpdateData();
GetDlgItemText(IDC_RADIO1 + radio1, strbuff);
MessageBox(strbuff);
}
void CMainDlg::OnBnClickedButton2()
{
CString resbuff, tempbuff;
UpdateData();
if (m_check1 == BST_CHECKED)
{
GetDlgItemText(IDC_CHECK1, tempbuff);
resbuff = resbuff + tempbuff;
}
if (m_check2 == BST_CHECKED)
{
GetDlgItemText(IDC_CHECK2, tempbuff);
resbuff = resbuff + tempbuff;
}
if (m_check3 == BST_CHECKED)
{
GetDlgItemText(IDC_CHECK3, tempbuff);
resbuff = resbuff + tempbuff;
}
if (m_check4.GetCheck() == BST_CHECKED)
{
m_check4.GetWindowTextW(tempbuff);
resbuff = resbuff + tempbuff;
}
MessageBox(resbuff);
}
添加注释:
// CMainDlg.cpp: 实现文件
//
// 引入必要的头文件
#include "afxdialogex.h" // MFC扩展对话框类的头文件
#include "CMainDlg.h" // 当前对话框类的头文件
#include "resource.h" // 资源ID定义头文件,包含对话框、控件等资源ID
// CMainDlg 对话框
// IMPLEMENT_DYNAMIC宏实现运行时类型信息(RTTI)
// 允许MFC框架在运行时动态创建和识别CMainDlg类
IMPLEMENT_DYNAMIC(CMainDlg, CDialogEx)
// 构造函数
// pParent: 父窗口指针,默认为nullptr表示无父窗口
CMainDlg::CMainDlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_DIALOG1, pParent) // 调用基类构造函数,指定对话框资源ID
, radio1(FALSE) // 初始化单选按钮变量为FALSE(未选中)
, m_check1(FALSE) // 初始化复选框1变量为FALSE(未选中)
, m_check2(FALSE) // 初始化复选框2变量为FALSE(未选中)
, m_check3(FALSE) // 初始化复选框3变量为FALSE(未选中)
{
// 构造函数体,这里为空,所有初始化在初始化列表中完成
}
// 析构函数
CMainDlg::~CMainDlg()
{
// 清理资源,这里为空,因为没有动态分配的资源需要清理
}
// DoDataExchange函数:MFC对话框数据交换(DDX)和数据验证(DDV)的核心函数
// pDX: CDataExchange对象指针,控制数据交换方向(对话框→变量或变量→对话框)
void CMainDlg::DoDataExchange(CDataExchange* pDX)
{
// 首先调用基类的DoDataExchange
CDialogEx::DoDataExchange(pDX);
// DDX_Radio: 关联单选按钮组与整型变量
// IDC_RADIO1: 单选按钮组的第一个按钮ID
// radio1: 关联的整型变量,存储选中的单选按钮索引(0表示第一个,1表示第二个,依此类推)
DDX_Radio(pDX, IDC_RADIO1, radio1);
// DDX_Check: 关联复选框与BOOL变量
// IDC_CHECK1: 复选框1的资源ID
// m_check1: 关联的BOOL变量,存储复选框1的状态(TRUE=选中,FALSE=未选中)
DDX_Check(pDX, IDC_CHECK1, m_check1);
DDX_Check(pDX, IDC_CHECK2, m_check2);
DDX_Check(pDX, IDC_CHECK3, m_check3);
// DDX_Control: 关联控件与控件类对象(用于直接访问控件成员函数)
// IDC_CHECK4: 复选框4的资源ID
// m_check4: CButton类对象,可以直接调用CButton的成员函数
// 注意:与前三个复选框不同,这里使用DDX_Control而不是DDX_Check
// 这意味着m_check4是一个控件对象,而不是简单的BOOL值
DDX_Control(pDX, IDC_CHECK4, m_check4);
}
// 消息映射宏:将Windows消息映射到类的处理函数
// BEGIN_MESSAGE_MAP(当前类, 基类)
BEGIN_MESSAGE_MAP(CMainDlg, CDialogEx)
// ON_BN_CLICKED: 按钮点击事件映射
// IDC_BUTTON1: 按钮1的资源ID
// &CMainDlg::OnBnClickedButton1: 对应的处理函数
ON_BN_CLICKED(IDC_BUTTON1, &CMainDlg::OnBnClickedButton1)
// IDC_BUTTON2: 按钮2的资源ID
ON_BN_CLICKED(IDC_BUTTON2, &CMainDlg::OnBnClickedButton2)
END_MESSAGE_MAP() // 消息映射结束
// CMainDlg 消息处理程序
// 按钮1的点击事件处理函数
void CMainDlg::OnBnClickedButton1()
{
CString strbuff; // 用于存储控件文本的字符串对象
// UpdateData: 更新对话框数据
// 参数为TRUE(默认)时:将控件值读取到关联的变量中
// 参数为FALSE时:将变量值更新到控件显示
UpdateData(); // 默认参数为TRUE,读取控件值到变量
// 获取选中的单选按钮的文本
// IDC_RADIO1 + radio1: 计算选中的单选按钮的ID
// radio1变量存储选中的单选按钮索引(0,1,2...)
// GetDlgItemText: 获取指定ID控件的文本
GetDlgItemText(IDC_RADIO1 + radio1, strbuff);
// 显示包含选中单选按钮文本的消息框
MessageBox(strbuff);
}
// 按钮2的点击事件处理函数
void CMainDlg::OnBnClickedButton2()
{
CString resbuff; // 结果字符串,存储所有选中复选框的文本
CString tempbuff; // 临时字符串,存储单个复选框的文本
UpdateData(); // 读取控件值到变量
// 检查第一个复选框是否被选中
// m_check1是BOOL变量,通过DDX_Check关联
// BST_CHECKED是Windows常量,表示选中状态
if (m_check1 == BST_CHECKED)
{
GetDlgItemText(IDC_CHECK1, tempbuff); // 获取复选框1的文本
resbuff = resbuff + tempbuff; // 追加到结果字符串
}
// 检查第二个复选框是否被选中
if (m_check2 == BST_CHECKED)
{
GetDlgItemText(IDC_CHECK2, tempbuff);
resbuff = resbuff + tempbuff;
}
// 检查第三个复选框是否被选中
if (m_check3 == BST_CHECKED)
{
GetDlgItemText(IDC_CHECK3, tempbuff);
resbuff = resbuff + tempbuff;
}
// 检查第四个复选框是否被选中
// m_check4是CButton对象,通过DDX_Control关联
// GetCheck(): CButton成员函数,返回复选框状态
if (m_check4.GetCheck() == BST_CHECKED)
{
// GetWindowTextW: 获取控件文本的宽字符版本
m_check4.GetWindowTextW(tempbuff);
resbuff = resbuff + tempbuff;
}
// 显示包含所有选中复选框文本的消息框
MessageBox(resbuff);
}
关键点说明:
1. DDX机制(对话框数据交换)
-
DDX_Radio: 处理单选按钮组
-
第一个参数是单选按钮组的起始ID
-
关联变量存储选中按钮的索引(0-based)
-
-
DDX_Check: 处理复选框的选中状态
-
关联变量为BOOL类型
-
-
DDX_Control: 关联控件与控件类对象
-
允许直接调用控件类的成员函数
-
2. 两种处理复选框的方式对比
| 方式 | 代码示例 | 特点 | 适用场景 |
|---|---|---|---|
| DDX_Check | DDX_Check(pDX, IDC_CHECK1, m_check1); | 简单的BOOL变量 | 只需获取选中状态 |
| DDX_Control | DDX_Control(pDX, IDC_CHECK4, m_check4); | CButton对象 | 需要调用控件方法(如GetCheck()) |
3. UpdateData()函数
-
UpdateData(TRUE): 控件值 → 变量(读取数据)
-
UpdateData(FALSE): 变量值 → 控件(更新显示)
4. 单选按钮组处理技巧
// 通过基ID + 索引的方式访问组内按钮
GetDlgItemText(IDC_RADIO1 + radio1, strbuff);
本文地址:https://www.yitenyun.com/6706.html










