MFC程序设计(一)MFC入门

本MFC教程使用VS2022实现

MFC基本概念

微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是一个微软公司提供的类库(class libraries),以C++类的形式封装了Windows API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。其中包含的类包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。

MFC把Windows SDK API函数包装成了几百个类,MFC给Windows操作系统提供了面向对象的接口,支持可重用性、自包含性以及其他OPP原则。MFC通过编写类来封装窗口、对话框以及其他对象,引入某些关键的虚函数(覆盖这些虚函数可以改变派生类的功能)来完成,并且MFC设计者使类库带来的总开销降到了最低。

编写MFC应用程序

我们将从一个空项目一步步的编写一个MFC应用程序

项目的创建

程序编写流程

MFC是由C++编写的用于创建和管理窗口相关功能的应用程序,因此创建MFC应用程序需要创建应用程序类和窗口类,并使应用程序对象关联窗口对象。

1.包含mfc头文件afxwin.h,仅需该头文件

2.自定义一个继承于CWinApp应用程序类的MyApp应用程序类,并实例化该应用程序类对象MyApp app(有且只有一个)

3.自定义一个继承于CFrameWnd窗口类(框架类)的MyFrame窗口类,并定义该窗口类的构造函数利用Create创建一个窗口

4.定义MyApp类虚函数:程序的入口函数InitInstance()。该函数用于创建窗口类MyFrame对象,并利用ShowWindow显示窗口,UpdateWindow更新窗口,m_pMainWnd保存窗口类对象指针,以此使得窗口可以正常运行

注意:ShowWindow和UpdateWindow属于CWnd类函数,m_pMainWnd为CWinThread类成员变量

代码的编写

框架类对象就是窗口对象

m_pMainWnd是CWinApp的父类CWinThread的一个数据成员,其保存了指向应用程序的主窗口的指针。此时m_pMainWnd = frame,使得该MFC应用程序能够管理我们创建的窗口frame

代码分析

CFrameWnd 框架窗口类

CFrameWnd是 从CWnd(窗口基类)派生出来的,用于模仿框架窗口行为。我们可以把框架窗口作为顶层窗口看待,它是应用程序与外部世界的主要接口。

如果想要创建一个窗口,可以在此类中调用CWnd::Create或CWnd::CreateEX函数:

cpp 复制代码
virtual BOOL Create
(
    LPCTSTR lpszClassName,
    LPCTSTR lpszWindowName,
    DWORD dwStyle,
    const RECT& rect,
    CWnd* pParentWnd,
    UINT nID,
    CCreateContext* pContext = NULL
);

1.Create接收的8个参数后6个有默认值定义,因此我们在上文使用的Create只写了两个参数

2.lpszClassName指定了窗口基于WNDCLASS类的名称,上文代码将其设定为NULL将创建一个基于已注册的WNDCLASS类的默认框架窗口。

3.lpszWindowName参数指定将在窗口的标题栏出现的文字。

CWinApp应用程序类

MFC应用程序的核心就是基于CWinApp类的应用程序对象。CWinApp提供了消息循环来检索消息并将消息调度给应用程序窗口。它还包括可被覆盖的、用来自定义应用程序行为的主要虚函数。

一个MFC程序可以有且仅有一个应用程序对象,此对象必须声明为在全局范围内有效,以便它在程序开始时即在内存中被实例化。

InitInstance函数

CWinApp::InitInstance函数是一个虚函数,其默认操作仅有一条语句:

cpp 复制代码
BOOL MyApp::InitInstance()//程序入口地址
{
  return TRUE;
}

InitInstance的目的是给应用程序提供一个自身初始化的机会,其返回值决定了框架接下来要执行的内容,如果返回FALSE将关闭应用程序,如果初始化正常返回TRUE以便允许程序继续进行。此函数是MFC应用程序的入口。

m_pMainWnd 成员变量

在CWinApp中有一个名为CWinThread::m_pMainWnd的成员变量。 该变量是一个CWnd类型的指针,它保存了应用程序框架窗口对象的指针。也就是指向CFramWnd对象(框架窗口类对象)的指针。

消息映射

消息映射是一个将消息和成员函数相互关联的表。比如,框架窗口接收到一个鼠标左击消息:WM_LBUTTONDOWN,MFC将搜索该窗口的消息映射,如果存在一个处理WM_LBUTTONDOWN的处理程序,然后就调用其对应的函数OnLButtonDown。

下面是是将消息映射添加到一个类中所做的全部工作:

1.在.h文件中的框架类,声明消息映射宏DECLARE_MESSAGE_MAP,作为将 Windows 消息与类的成员函数相关联的表。

2.在.cpp文件中利用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP表消息映射的范围,即分界宏。在分界宏中写入要定义的消息宏,该宏用于找到消息对应的处理函数。

3.在.h文件中写入消息处理函数的原型声明

4.在.cpp文件中实现该函数

每个消息映射入口都对应一个唯一的消息处理函数,从msdn帮助手册查询

简单的理解:DECLARE_MESSAGE_MAP就是一个函数表,BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间的范围表示函数表的范围,表中的每一项都是函数的入口,每个入口都对应特定的函数

上图中ON_WM_LBUTTONDOWN表鼠标左键按下的消息

3.消息处理函数 在.h文件类中声明,.cpp文件定义:

该OnLButtonDown函数可在我们在窗 口中点击函数时,弹出显示鼠标左键

我们也可以把OnLButtonDown重新定义

void MyFrame :: OnLButtonDown(UINT, CPoint point)
{
    //TCHAR buf[1024];
    //wsprintf(buf, TEXT("x = %d, y = %d"), point.x, point.y);
    //MessageBox(buf);
    CString str;
    str.Format(TEXT("x = %d, y = %d", point.x, point.y));
    MessageBox(str);
}

该代码两种方式都可以在点击窗口时弹窗显示坐标

我们同样也可以添加一个键盘的消息映射,此处不再演示

此时,我们便完成了一个简单的mfc程序,该程序也具有一个功能

帮助文档的使用

MSDN的使用

VC++之MFC类库中文手册

通过此手册查找,必须加上成员所属的类作用域(类名::),否则,无法查找到匹配的关键字。

实际上,我们在使用VS进行编程遇到不熟悉的函数时,直接按F1查看帮助即可

向导生成基于单文档MFC应用程序

在我们实际编程中,我们并不需要从0创建一个mfc应用程序,VS为我们提供好了现成的模板使用,这也叫做工程文件。接下来我们将演示如何利用VS向导创建一个单文档MFC标准类型应用程序。

MFC为我们生成了如上四个类:App,MainFrame,View,Doc

APP继承于CWinApp:应用程序类

MainFrame继承于CFrameWnd:框架类,类比相框。在此类中写代码显示东西是显示不出来的,被覆盖掉了。这与我们前文学习的在框架类中弹窗显示坐标产生了区别

View继承于CView:视图类,用于显示内容,类比相片。在此类中写代码显示东西才能显示出来

Doc继承于CDocument:文档类,用于存储和管理数据

点击完成以后,我们便创建成功了,运行结果如下:

类视图

在mfc开发中,我们通常不再使用解决方案资源管理器,而是使用类视图。在类视图中可以找到MFC中的类

CAboutDlg:对话框类,由MFC向导自行生成,用于显示应用程序的 "关于" 信息,如下图所示,没啥用

双击相应的类名便可跳转到类声明所在的.h文件

下方框为类中成员函数,双击即可跳转到相应定义部分

文档/视图结构体系

MFC应用程序框架结构的基石是文档/视图体系结构,它定义了一种程序结构,这种结构依靠文档对象保存应用程序的数据,并依靠视图对象控制视图中显示的数据,把数据本身与它的显示分离开。

数据的存储和加载由文档类来完成,数据的显示和修改则由视类来完成。 MFC在类CDocument和CView中为稳定视图提供了基础结构。CWinApp、CFrameWnd和其他类与CDocument和CView合作,把所有的片段连在了一起。

CView类也派生于CWnd类,框架窗口是视图窗口的一个父窗口。主框架窗口(CFrameWnd)是整个应用程序外框所包括的部分,即图中粗框以内的内容,而视类窗口只是主框架中空白的地方。

消息处理的添加

在主框架类中添加WM_LBUTTONDOWN消息的响应函数,具体操作如下:

从类视图中找到CMainFrame(继承自CFrameWnd),选择此类然后从属性面板中找到消息按钮

在消息列表中找到WM_LBUTTONDOWN消息,添加。

我们同样也可以轻松删除,但删除的形式是注释而非代码删除

工程文件增加几处改变:

第一处:在框架类头文件中添加了鼠标左键消息函数的函数声明

第二处:在框架类cpp文件中添加了消息映射宏

第三处:在框架列cpp文件中添加了处理鼠标左键消息的函数定义

接下来我们在此OnLButtonDown函数中添加一个MessageBox消息,鼠标左键按下弹出一个提示框

执行程序,我们会惊奇的发现程序并未如我们所愿弹出消息框。

因为,框架窗口是视窗口的父窗口,那么视类窗口就应该始终覆盖在框架类窗口之上。就好比框架窗口是一面墙,视类窗口就是墙纸,它始终挡在这面墙前边。也就是说,所有操作,包括鼠标单击、鼠标移动等操作都只能有视类窗口捕获。因此当我们把上述的操作全部删除以后,在View类中重现,就会发现,此时点击鼠标左键会弹窗

MFC框架中一些重要的函数

InitInstance函数

应用程序类的一个虚函数,MFC应用程序的入口。

PreCreateWindow函数

当框架调用CreateEx函数创建窗口时,会首先调用PreCreateWindow函数。

通过修改传递给PreCreateWindow的结构体类型参数CREATESTRUCT,应用程序可以更改用于创建窗口的属性。在产生窗口之前让程序员有机会修改窗口的外观。

最后再调用CreateWindowEx函数完成窗口的创建。

OnCreate和Create

OnCreate是一个消息响应函数,是响应WM_CREATE消息的一个函数,而WM_CREATE消息是由Create函数调用的。一个窗口创建(Create)之后,会向操作系统发送WM_CREATE消息,OnCreate()函数主要是用来响应此消息的。

OnCreate与Create的区别:

1.Create()负责注册并产生窗口,像动态创建控件中的Create()一样,窗口创建成功之后会向操作系统发送WM_CREATE消息。

2.OnCreate()不产生窗口,只是在窗口显示前设置窗口的属性如风格、位置等。

3.OnCreate()是消息WM_CREATE的消息响应函数。

OnDraw和OnPaint

OnPaint()是CWnd的类成员,负责响应WM_PAINT消息。

OnDraw()是CView的成员函数,没有响应消息的功能。

OnPaint是WM_PAINT消息的消息处理函数,OnDraw是OnPaint中调用的一部分。一般来说,用户自己的绘图代码应放在OnDraw中。

当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows发送WM_PAINT消息。该视图的OnPaint 处理函数通过创建CPaintDC类的DC对象与当前窗口关联并做一些准备工作。然后OnPaint 调用视图的OnDraw成员函数,将DC对象传递给OnDraw成员函数,让该函数使用DC进行具体绘画操作。

通常我们不必编写OnPaint处理函数,这是因为在View类里添加了消息处理OnPaint()时,OnPaint()就会覆盖掉OnDraw()。

我们在这两个函数中,分别在同一个位置显示不同的文案,观察程序运行的结果

拓展知识点

MFC中后缀名为Ex的函数都是扩展函数。

在MFC中,以Afx为前缀的函数都是全局函数,可以在程序的任何地方调用它们

注意:消息处理函数中的afx_msg只是一个标识符

相关推荐
一只小bit1 小时前
C/C++内存管理(超详解)
开发语言·c++
智驾3 小时前
C++,设计模式,【目录篇】
c++·设计模式
汤姆和杰瑞在瑞士吃糯米粑粑3 小时前
【优先算法】滑动窗口--结合例题详解学习
开发语言·数据结构·c++·算法
轻口味3 小时前
【HarmonyOS NAPI 深度探索10】HarmonyOS Next 中的 NAPI 的架构与原理
c++·华为·架构·harmonyos·napi·harmonyos-next
编程乐趣3 小时前
盘点下5个Winform UI开源控件库
ui·开源·mfc
我们的五年3 小时前
【C++课程学习】:C++中的IO流(istream,iostream,fstream,sstream)
linux·c++·学习
ExRoc5 小时前
蓝桥杯真题 - 异或和之差 - 题解
c++·算法·蓝桥杯
Python_enjoy5 小时前
洛谷题解 - P1003 [NOIP2011 提高组] 铺地毯
数据结构·c++·算法
明月醉窗台6 小时前
C++ 之多线程相关总结
开发语言·c++·算法
掂过碌蔗呀7 小时前
Java调用C/C++那些事(JNI)
java·c语言·c++