基本概念
SDK:开发软件的套件
WDK:开发驱动的套件
当我们开发驱动时,两者版本需要一致
MFC:Microsoft Fundation class,即微软基础类库。是基于Win32 SDK进行的封装的框架 。
MFC为我们提供了大量的WindowsSDK的代码及设计重用,因此我们并不需要像SDK一样对消息过程进行处理,而是只需要去实现相应消息的功能即可
接下来我们开始从0到1创建一个最常见的MFC项目(基于对话框):
我们打开VS2022,选择创建MFC应用:
1.应用程序类型->修改基于对话框
2.用户界面功能->依自己想法进行选择
3.将该项目命名为Demo01
二.修改相关项目属性:
1.属性->C/C++/代码生成/运行库->MTD ,Spectre缓解->禁用,
2.属性->高级->MFC的使用->在静态库中使用MFC
完成以上设置后,我们运行程序,便得到了一个基于对话框的mfc窗口
现在我们创建一个单文档MFC项目:
一.我们打开VS2022,选择创建MFC应用:
1.应用程序类型->修改当个文档
2.项目样式->MFC standard
二.修改相关项目属性:
1.属性->C/C++/代码生成/运行库->MTD ,Spectre缓解->禁用,
2.属性->高级->MFC的使用->在静态库中使用MFC
3.注意不要关闭预编译头
完成以上设置后,我们运行程序,便得到了一个单文档的mfc窗口
接下来我们以同上单文档mfc同样的操作创建一个多文档的mfc项目
如下图所示:
WINDBG就是通过多文档MFC开发的
接下来我们创建一个单文档的Windows Explorer样式的MFC项目
如下图所示:
接下来我们创建一个单文档的office样式的Windows7视觉样式的mfc项目
如下图所示:
接下来我们创建一个单文档的VsStudio样式2018视觉央视的mfc
如下图所示:
接下来我们以上面创建的基于对话框的mfc项目进行讲解
MFC类管理
我们在该项目的类视图中可以发现,该项目有如下几个类
CAboutDlg:应用程序的主对话框点击关于弹出的对话框类
CDemo01App: CWinApp 派生的类
CDemo01Dlg:主对话框类,应用程序运行后显示的主要界面
Demo01Dlg类是一个多重继承的类,它的继承关系自顶向下分别是:
Cobject:最父类。基础类库中的主体基类,用于处理序列化以及反序列化:类似我们将结构体存储到文件,再从文件中取出该结构体的过程
CCmdTarget:消息映射结构体系类,该类可以处理WM_COMMAND消息
CWnd:窗口类
CDialog:对话框类
CDialogEx:对话框类
Demo01Dlg:最子类,我们自己创建的对话框
OnInitDialog:对话框MFC框架的入口
MFC是基于类的管理,在运行程序后生成的对话框默认绑定了一个类:Demo01Dlg,两者一一关联。
MFC函数
在MFC中,我们需要使用Windows SDK的所有需要填写窗口句柄的函数,均不需要填写窗口句柄。这是因为MFC对SDK的函数进行了二次封装。
比如:MessageBox(L”Msg”, L”Msg”, MB_OK)
但如果我们需要调用WindowsSDK本身的函数时,只需要在函数前加入::进入全局命名空间,,这时便退出了MFC的命名空间,这样便可以正常调用了
比如:
HWND hStatic = ::GetDlgItem(m_hWnd, IDC_STATIC);
::SetWindowText(hStatic, L”MSG”);
对话框
MFC中的对话框分为模态对话框和非模态对话框,和SDK一致,并且同样支持SDK通过发消息的形式对对话框的应用
现在我们进行讲解一个对话框从0到1的创建过程:
1.我们在资源中手动添加一个对话框后,右键点击后选择添加类:
如下图所示:
2.对添加的类进行相关设置
此时MFC会自动生成该对话框类以及CDialogOne.h类声明和CDialogOne.cpp类实现文件,而对话框中的控件就是类对象
按钮
现在我们进行讲解如何添加按钮并应用:
我们以程序为我们生成的主对话框为例,进行按钮的添加及应用
1.我们手动在主对话框中添加以下两个按钮
2.针对按钮进行应用:点击相关按钮,右键点击后选择事件处理程序。此处双击按钮可以创建点击消息类型的处理函数
3.对事件处理程序进行填写内容,此处我们选择的是点击的消息类型。注意该按钮在哪个对话框,就要把他放在相应对话框的类里。我们也可以选择其他消息类型以便我们对其进行相关消息触发后的处理。
4.我们同样可以右键对话框选择类向导,在类向导中,有很多可供我们选择的控件的各种消息处理
5. 我们也可以在按钮属性的控件事件(黄色闪电)中进行添加相关消息处理函数
6.完成以上步骤以后,程序会为我们生成相关的控件消息处理函数,我们直接在该函数内部进行函数定义即可
MFC在每个控件都实现了很多的函数了,我们直接使用即可。上述代码的含义是点击按钮后弹出一个对话框
此时我们便完成了MFC中对控按钮的一个应用了
编辑框
现在我们进行讲解编辑框的创建与应用
我们对控件进行应用时,控件的数据可能会发生变化,比如编辑框文本编辑。因此我们需要为这些数据可能发生变化的控件进行绑定变量。上文中的按钮,以及静态文本之类的控件,由于我们应用时并不会导致相关数据发生变化,因此我们不必进行绑定变量
MFC控件绑定变量的两种方式:
1.值类型
2.控件类型
接下来,我们针对编辑框对两种类型的绑定进行一个讲解
1.我们在对话框中创建两个文本编辑框
2.右键点击第一个编辑框选择添加控件变量,之后我们对此进行内容的填写
此时第一个编辑框便是控件类型绑定
3.右键点击第二个编辑框选择添加控件变量,之后我们对此进行内容的填写
此时第二个编辑框便是值类型绑定
现在我们开始对这两种不同变量绑定的编辑框结合按钮进行应用:
void CDemo01Dlg::OnBnClickedButtonCreateDialog()
{
//控件类型编辑框应用:
// 应用一:点击按钮弹出模态对话框
CDialogOne obj;
obj.DoModal();
//应用二:点击按钮使控件类型编辑框显示文本
//方法一:使用SDK的函数
HWND hEdit1 = ::GetDlgItem(m_hWnd, IDC_EDIT1);//获取编辑框1的句柄
::SetWindowText(hEdit1, L"Text");//点击模态按钮编辑框1显示文本Text
//方法二:使用类中函数
m_Edit1.SetWindowTextW(L"xxxxx");//点击模态按钮编辑框1显示文本xxxxx
//应用三:点击按钮使值类型编辑框显示文本:
UpdateData(TRUE); //首先需要进行文本与界面的同步
m_Edit2 = L"xxxxx";//值类型的编辑框可以直接编辑
UpdateData(FALSE);//同步首尾对应
}
在SDK中SendMessage和PostMessage处理的消息在MFC对应OnWndMsg和PreTranslateMessage。因此我们可以在这两个函数中像SDK一样处理消息
现在我们在对此进行实践:
//Post
BOOL CDemo01Dlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: 在此添加专用代码和/或调用基类
switch (pMsg->message)
{
case 12138:
{
switch (pMsg->wParam)
{
case 119:
{
MessageBox(L"119", L"Msg", MB_OK);
break;
}
case 120:
{
MessageBox(L"120", L"Msg", MB_OK);
break;
}
case 121:
{
MessageBox(L"121", L"Msg", MB_OK);
break;
}
default:
break;
}
break;
}
default:
break;
}
return CDialogEx::PreTranslateMessage(pMsg);
}
BOOL CDemo01Dlg::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
// TODO: 在此添加专用代码和/或调用基类
switch (message)
{
case 12138:
{
switch (wParam)
{
case 119:
{
MessageBox(L"119", L"Msg", MB_OK);
break;
}
case 120:
{
MessageBox(L"120", L"Msg", MB_OK);
break;
}
case 121:
{
MessageBox((WCHAR*)lParam, L"Msg", MB_OK);
break;
}
default:
break;
}
break;
}
default:
break;
}
return CDialogEx::OnWndMsg(message, wParam, lParam, pResult);
}
现在我们在模态按钮上进行如上消息的应用
void CDemo01Dlg::OnBnClickedButtonCreateDialog()
{
//PostMessage(12138, 119, NULL);
//PostMessage(12138, 120, NULL);
//PostMessage(12138, 121, L”abc”);
现在我们在模态按钮上进行如上消息的应用
void CDemo01Dlg::OnBnClickedButtonCreateDialog()
{
//PostMessage(12138, 119, NULL);
//PostMessage(12138, 120, NULL);
//PostMessage(12138, 121, L”abc”);
}
由于post消息不阻塞,所以这三个post消息会一起发送给程序,因此这三个消息的执行顺序并不一样正常。但是如果是Send消息,则会顺序执行
注意:对话框只有一个消息循环且只有一个线程。当对话框消息处理函数无法结束时,POST和SEND会把消息发送给消息队列。POST会直接返回,而不是一直等到消息处理的结果。而SEND会等待结果,之后再返回