简介
MFC(Microsoft Foundation Class Library,微软基础类库)是微软推出的一个 C++ 类库,主要用于 Windows 平台下的应用程序开发。它封装了 Windows API(应用程序接口)的复杂细节,提供了一套面向对象的编程框架,简化了 Windows 应用程序的开发过程。
核心特点:
-
面向对象封装:MFC 将 Windows API 中的结构体、函数等封装成类,例如窗口(CWnd)、对话框(CDialog)、按钮(CButton)等,开发者可以通过继承和多态等面向对象特性快速构建应用。
-
消息映射机制:MFC 提供了消息映射(Message Mapping)机制,将 Windows 的消息(如鼠标点击、键盘输入)与类的成员函数关联,简化了消息处理流程,无需手动编写复杂的回调函数。
-
文档 / 视图架构:MFC 的文档 / 视图(Document/View)结构是其核心设计之一,将数据管理(文档,CDocument)与数据显示(视图,CView)分离,适合开发需要处理复杂数据并进行多视图展示的应用(如文本编辑器、图像浏览器)。
-
丰富的控件支持:内置了大量常用的 Windows 控件(按钮、文本框、列表框、树控件等)的封装类,同时支持自定义控件开发。
与 Windows 系统深度集成:直接调用 Windows 底层功能,支持多线程、网络编程、数据库访问(通过 ODBC 或 OLE DB)、ActiveX 控件等 Windows 特性。
对话框
以 vs 2022 为例。
创建后的文件结构
framework.h
- 包含了 MFC 框架中一些基础的头文件,定义了一些常用的宏、类型定义和基础类声明。它是 MFC 框架的基础包含文件,为整个项目提供了必要的基础定义和类型支持,使得项目能够正确使用 MFC 框架中的各种功能。
MFCApplication1.h
- 这是应用程序类的头文件。应用程序类通常从CWinApp派生,在这个类中,会处理应用程序的初始化、运行和终止等操作,比如初始化全局资源、创建主窗口(在基于对话框的应用中就是创建对话框窗口)、处理消息循环等。
MFCApplication1Dlg.h
- 定义了应用程序主对话框类,这个类通常从CDialogEx派生(CDialogEx是CDialog的扩展版本,提供了更多现代化的对话框特性)。在这个头文件中,会声明对话框上控件对应的成员变量(通过DDX_ 宏关联),以及对话框处理各种消息(如按钮点击、菜单选择等)的成员函数(通过ON_宏映射) 。
pch.h
- 预编译头文件。它包含了项目中经常使用的头文件,比如 MFC 的核心头文件。Visual Studio 可以对这个头文件进行预编译,生成预编译头文件(.pch 文件),在编译其他源文件时,直接使用预编译头文件,从而加快编译速度。
Resource.h
- 资源符号定义文件,用于定义项目中各种资源(如对话框、菜单、图标等)的 ID。当在 Visual Studio 的资源编辑器中创建或修改资源时,对应的资源 ID 会自动在这个文件中进行定义,方便在代码中引用这些资源。
targetver.h
- 定义了目标 Windows 平台的版本信息,通过宏来指定要支持的 Windows 版本。它帮助编译器根据不同的 Windows 版本要求,进行相应的代码调整和编译设置,以确保应用程序在目标 Windows 系统上能够正确运行。
MFCApplication1.ico
- 应用程序的图标文件,用于在 Windows 资源管理器、任务栏等位置显示应用程序的图标。当应用程序运行时,任务栏上的程序图标、窗口左上角的图标等,默认就是这个文件所指定的图标。
MFCApplication1.rc
- 资源脚本文件,用于描述应用程序中所有资源的信息。它包含了对话框的布局、菜单的定义、图标、字符串表等资源的详细描述,是资源编辑器和编译器之间的桥梁。在编译过程中,编译器会根据这个文件来生成对应的二进制资源文件,以便应用程序在运行时能够加载和使用这些资源。
MFCApplication1.rc2
- 辅助资源脚本文件,主要用于存放一些在 Visual Studio 的资源编辑器中无法编辑的资源,比如自定义的位图、光标等。一般情况下,它用于补充和扩展.rc文件中的资源定义。
修改标题
点击对话框,【属性】=》【描述文字】
插入对话框
在资源视图中选择对话框-右击选择插入
然后右击对话框,选择添加类
模态对话框
- 打开后,用户只能操作该对话框,其他窗口(包括父窗口)被阻塞
- 对话框关闭后,对象通常被销毁(资源释放)
- 需用户立即响应的操作(如 “确定 / 取消”“设置参数”)
- 用 DoModal() 创建,关闭时自动销毁
示例
插入一个对话框,并创建类ModalDlg
, 添加static text,内容为 “模态对话框”。 在主对话框中 添加一个按钮 “模态对话框”,并双击创建处理函数。
// 在MFCApplication1Dlg.cpp 中导入ModalDlg
#include "ModalDlg.h"
void CMFCApplication1Dlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
ModalDlg dlg;
dlg.DoModal();
}
非模态对话框
- 打开后,用户可自由切换到其他窗口(包括父窗口)操作
- 对话框关闭后,对象可保留(需手动销毁)
- 长期存在的辅助窗口(如 “工具栏”“属性面板”)
- 用 Create() 创建,需手动调用 DestroyWindow() 销毁
插入一个对话框,并创建类ModalessDlg
, 添加static text,内容为 ”非模态对话框”。 在主对话框中 添加一个按钮 “非模态对话框”,并双击创建处理函数。
void CMFCApplication1Dlg::OnBnClickedButton3()
{
// TODO: 在此添加控件通知处理程序代码
ModalessDlg* dlg = new ModalessDlg(this);
if (dlg->Create(IDD_DIALOG2, this))
{
// 显示对话框
dlg->ShowWindow(SW_SHOW);
}
else
{
// 创建失败时清理
delete dlg;
dlg = NULL;
}
}
控件
static text
从工具栏中找到static text ,拖动到对话框中,选中后修改内容,可直接输入修改,也可从属性栏中修改。
添加变量
默认是不能添加的,修改修改ID,将 ID 修改为 IDC_STATIC1。
右击选择添加变量。
在类别中有两个选项, 控件(变量类型为 CStatic)、值(变量类型为CString),
添加后,在MFCApplication1Dlg.h
生成 CString m_s1;
,
在MFCApplication1.cpp 中添加 初始化和数据交换绑定
CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_MFCAPPLICATION1_DIALOG, pParent)
, m_s1(_T(""))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_STATIC1, m_s1);
}
修改值
在OnInitDialog 中添加
BOOL CMFCApplication1Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
//...
m_s1 = "hello mfc";
UpdateData(FALSE);
//...
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
其中UpdateData(FALSE)
表示将变量的内容传递给控件,TRUE
则相反。
若添加的时CStatic 对象,则使用SetWindowTextW
m_s2.SetWindowTextW(_T("static control"));
button
拖动按钮到对话框即可添加
绑定处理事件
添加后双击,会自动生成
BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
ON_BN_CLICKED(IDC_BUTTON1, &CMFCApplication1Dlg::OnBnClickedButton1)
END_MESSAGE_MAP()
void CMFCApplication1Dlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
}
或者右击使用类向导添加
_T
在 MFC 中,_T() 是一个宏,用于实现字符串的Unicode/ANSI 兼容性,是处理字符串时非常重要的宏定义。
作用说明:
- _T(“字符串”) 会根据项目的字符集设置,自动将字符串转换为对应的编码格式:
- 当项目使用 Unicode 字符集(默认设置)时,_T(“abc”) 等价于 L"abc"(宽字符字符串,wchar_t 类型)。
- 当项目使用 多字节字符集 时,_T(“abc”) 等价于 “abc”(窄字符字符串,char 类型)。
使用场景:
- 在 MFC 中,很多函数都有两个版本(如 CString 的构造、MessageBox 等):
- Unicode 版本:函数名后缀带 W(如 MessageBoxW),接收宽字符字符串。
- ANSI 版本:函数名后缀带 A(如 MessageBoxA),接收窄字符字符串。
使用 _T() 宏后,代码可以在两种字符集下兼容编译,无需手动修改字符串格式。
CString
CString 是 MFC 中最常用的字符串类,功能强大且易用,支持 Unicode 和 ANSI 字符集,是处理字符串的核心工具。
- 依赖项目字符集设置,默认是 Unicode(CStringW,宽字符 wchar_t),也可配置为 ANSI(CStringA,单字节 char)。
- 通常直接使用 CString,会根据宏自动映射为 CStringW 或 CStringA。
- 无需手动分配 / 释放内存,析构时自动释放,避免内存泄漏。
- 可与 const char*、const wchar_t* 互转,也支持与 std::string/std::wstring 转换。
初始化与赋值
// 初始化
CString str1 = _T("Hello"); // 使用 _T 宏兼容字符集
CString str2(_T("MFC"));
CString str3;
str3 = _T("String"); // 赋值
// 从 C 字符串转换
const char* cstr = "test";
CStringA strA(cstr); // ANSI 版本
CStringW strW(L"宽字符"); // Unicode 版本
字符串拼接
CString str = _T("Hello");
str += _T(" World"); // 结果: "Hello World"
str = str + _T("!"); // 结果: "Hello World!"
// 格式化拼接(类似 sprintf)
int num = 100;
str.Format(_T("Number: %d, String: %s"), num, _T("test")); // 结果: "Number: 100, String: test"
长度与判空
CString str = _T("Hello");
int len = str.GetLength(); // 长度: 5(字符数,非字节数)
BOOL isEmpty = str.IsEmpty(); // 是否为空: FALSE
str.Empty(); // 清空字符串
isEmpty = str.IsEmpty(); // TRUE
比较操作
CString str1 = _T("Apple");
CString str2 = _T("apple");
// 比较(返回 0 表示相等)
int cmp = str1.Compare(str2); // 区分大小写: 结果非 0
cmp = str1.CompareNoCase(str2); // 不区分大小写: 结果为 0
// 包含判断
BOOL contains = str1.Find(_T("pp")) != -1; // 是否包含 "pp": TRUE
截取与替换
CString str = _T("Hello,World");
// 截取子串(从索引 7 开始,取 5 个字符)
CString sub = str.Mid(7, 5); // 结果: "World"
// 替换
str.Replace(_T("World"), _T("MFC")); // 结果: "Hello,MFC"
// 移除字符
str.Remove(_T(',')); // 结果: "HelloMFC"
与标准库转换
// CString -> std::string(ANSI)
CStringA strA(_T("test"));
std::string stdStr(strA.GetBuffer());
strA.ReleaseBuffer(); // 释放缓冲区
// CString -> std::wstring(Unicode)
CStringW strW(_T("宽字符"));
std::wstring stdWstr(strW.GetBuffer());
strW.ReleaseBuffer();
数值转换
// 字符串转数值
CString strNum = _T("123.45");
int n = _ttoi(strNum); // 123(_ttoi 兼容 Unicode/ANSI)
double d = _tstof(strNum); // 123.45
// 数值转字符串
int num = 678;
CString str;
str.Format(_T("%d"), num); // "678"
CString , CStringA, CStringW
类型 | 字符集 | 底层字符类型 | 适用场景 |
---|---|---|---|
CStringW | Unicode(宽字符) | wchar_t | 处理宽字符字符串(如中文、日文等多字节字符) |
CStringA | ANSI(窄字符) | char | 处理单字节字符串(如英文字符) |
CString | 自适应字符集 | 取决于宏定义 | 根据项目设置自动映射为 CStringW 或 CStringA |
CStringA 与 CStringW 互转
// ANSI -> Unicode
CStringA strA("ANSI字符串");
CStringW strW(strA); // 直接构造转换(内部使用 MultiByteToWideChar)
// Unicode -> ANSI
CStringW strW(L"Unicode字符串");
CStringA strA(strW); // 直接构造转换(内部使用 WideCharToMultiByte)
与 C 风格字符串互转
// CStringA <-> const char*
CStringA strA("test");
const char* cstrA = strA.GetBuffer(); // 获取 char* 指针
strA.ReleaseBuffer(); // 用完后释放
// CStringW <-> const wchar_t*
CStringW strW(L"测试");
const wchar_t* cstrW = strW.GetBuffer(); // 获取 wchar_t* 指针
strW.ReleaseBuffer();
与标准库字符串互转
// CStringA <-> std::string
CStringA strA("hello");
std::string stdStr(strA.GetBuffer());
strA.ReleaseBuffer();
// CStringW <-> std::wstring
CStringW strW(L"世界");
std::wstring stdWstr(strW.GetBuffer());
strW.ReleaseBuffer();