1 C++MFC应用程序框架类结构层次

图1 MFC类结构关系图
2 MFC类的继承关系与用途
MFC中文全称“微软基础类库”, 是微软公司开发的一套基于C++的面向对象的Windows图形用户界面应用程序开发框架。它提供了一套完整的基于Windows平台的图形界面应用程序开发工具包,包括窗口管理、控件、绘图、网络、数据库等,它以C++类的形式封装了Windows API。
2.1 MFC应用程序类型
MFC应用程序中的类至少包含一个应用程序类和一个窗口框架类,其有三种典型的应用程序:
- 基于对话框的应用程序:这类程序适合于文档较少而交互操作较多的应用场合,如 Windows 自带的计算器程序。
- 单文档界面( SDI )应用程序:这类程序一次只能打开一个文档,如 Windows 自带的 Notepad 程序。
- 多文档界面( MDI )应用程序:这类程序可以同时打开多个文档并进行处理,处理的过程中很容易地进行切换,如 Microsoft Word 。
注意:数据的存储和加载由文档类来完成,数据的显示和修改则由视类来完成,把数据管理和显示方法分离开来。文档/视结构是MFC程序的一个重点。
2.2 MFC应用程序框架C++类的种类及继承关系
MFC大约有200个类,分为两种,一是CObject基类的派生类,它们以层次结构的形式组织起来,几乎每个子层次结构都与一个具体的 Windows 实体对应,二是非 CObject 派生类,这些都是独立的类,如表示点的 CPoint 类,表示矩形的 CRect 类。
MFC所有类中除了基类,其他类都是通过C++类的继承特性建立联系。MFC类主要分为应用程序结构类、窗口支持类、图像设备类、模版集合类、简单数据类型类以及全局AFX函数等6个类。Afx前缀的函数代表应用程序框架(Application Framework)函数,属于全局函数,它们可以在程序的任何地方被调用。
(1)应用程序结构类
应用程序结构类代表的是应用程序的基本元素,主要是CCmdTarget类与它的派生类。其中CWinThread/CWinApp类,负责整个程序的执行流程。关系如下所示。
- CCmdTarget类:是MFC类库中消息映射体系的基类,继承于Cobject类。该类负责把消息命令传递给用户编写的消息响应函数,如果需要处理消息,则从CcmdTarget类中派生一个类出来,但很少从CCmdTarget类直接派生类出来用。
- CWinThread类:CWinThread类继承于CCmdTarget类。CWinThread类的对象代表应用程序内部运行的线程。运行的主线程通常由CwinApp类的派生类提供。并CwinThread类支持两种线程:工作线程和用户界面线程。工作线程不能够发送、接收消息,通常用于后台运行。用户界面线程能够发送和接收消息。
- CWinApp类:CWinApp类表示应用程序类,在使用MFC创建的所有应用程序中,都包含一个继承于该类的应用程序子类。CwinApp类中封装了windows的消息循环机制,并负责应用程序的初始化和退出的清理工作。创建工程时生成的用户应用程序类就继承自CWinApp类。
- CDocument类:CDocument类是文档类继承于CCmdTarget类。提供了文档的基本功能,并且CDocument类是Document/View结构中的应用程序文档的基类,主要用于代表程序中的数据。
- CDocTemplate类:CDocTemplate类继承于CCmdTarget类。定义了文档模版的基本函数功能。通常通过应用程序类的InitInstance函数来创建一或多个文档模版。文档模版定义了框架,文档和视图三个类之间的关系。
(2)窗口支持类
窗口支持类包含了基于Windows应用程序的一些可视性元素,如窗口,对话框,控件等。窗口支持类中的所有类都是从CWnd类中派生的,包括CFrameWnd类,CDialog类,CView类等。关系如下所示。
- CWnd类:CWnd类继承于CCmdTarget类。CWnd类提供了MFC中所有窗口类的基本功能。根据窗口的不同类型,CWnd类派生出了许多子类,如框架窗口类CFrameWnd,对话框类CDialog,视图类CView等。以及对处理一些系统消息。
- CFrameWnd类:CFrameWnd类继承于CWnd类。它是框架窗口类,封装对各种框架窗口的操作。
- CDialog类:CDialog类继承于CWnd类。CDialog对话框类是在屏幕上显示的对话框的基类。CDialog类对象是对话框模版与一个CDialog派生类的组合,通过使用对话框编辑器创建对话框并存入资源之中,然后为对话框创建一个CDialog派生类。
- CView类:CView类继承于CWnd类。CView视图类是应用程序框架窗口中的子窗口,视图是用户与文档交互的媒介,用户可以在视图窗口内输入文本,绘图等。
- 控制类:控制类很多种,基本上都继承自CWnd类。例如CButton类,CEdit类等。
(3)图像设备类
MFC提供图形设备类中包含了设备环境(Device Context)类,以及一些常用的GDI对象。设备环境类中包含了一组绘制图形的函数集合,以及确定绘图的模式和绘图的映射模式。绘图对象类封装了常用GDI绘图对象,包括画笔(Pen),刷子(Brush),字体(Font),位图(Bitmap),调色板(Palette)和区域(Region)。
CDC类是所有设备环境的基类,该类封装了所有图形输出函数。CDC类派生了CClientDC类、CMetaFileDC类,CPaintDC类以及CWindowDC类。关系如下所示。
- CClientDC类:CClientDC类主要提供了对窗口的客户区域的图形操作。窗口的客户区域是排除窗口的框架,标题栏,菜单栏,工具栏和状态栏的区域。
- CMetaFileDC类:CMetaFileDc类专门用于图元文件的绘制。图元文件记录一组GDI命令,可以通过这一组GDI命令重建图形输出。使用CMetaFileDC时,所有的图形输出命令会自动记录到一个与CMetaFileDC相关联的图元文件中。
- CPaintDC类:CPaintDC类是响应WM_PAINT消息的设备环境。当窗口需要重绘时,应用程序响应OnPaint消息来刷新窗口的实现,CPaintDC类通常在MFC应用程序的OnPain函数中使用。
- CWindowDC类:CWindowDC类可以提供在整个窗口内绘图的设备环境,该设备环境可以用于窗口客户区和非客户区的绘制,除非用户需要单独绘制窗口边框和按钮,否则一般不使用CWindowDC环境。
- (4)模版集合类
模版集合类主要分为3个部分:数组类,链表类和映射类,在这里暂不做详细总结。
(5)简单数据类型类
简单数据类型类定义了一些常用的数据类型,包括CPoint类,CSize类,CRect类,CString类和CTime类。分别代表点,尺寸大小,矩形区域,字符串和日期时间,这些都是MFC中常用的数据类型。
(6)全局AFX函数
由于C++不是完全的面向对象,为了让各个类结合在一起,就要定义一些全局函数(在每个类中都可以使用,是MFC的应用程序框架函数)。Afx前缀的函数代表应用程序框架(Application Framework)函数。应用程序框架实际上是一套辅助我们生成应用程序的框架模型。该模型把多个类进行了一个集成。MFC类库主要可以分为两个部分:MFC类和宏与全局函数。举例如下所示。
- AfxMessageBox函数:显示一个消息提示框,功能与MessageBox相同。
- AfxGetApp函数:取得应用程序中唯一的CWinApp对象的指针。
- AfxGetAppName函数:返回一个包含应用程序名字的字符串。
- AfxGetInstance函数:获取当前运行实例的句柄。
- AfxGetThread函数:取得指向当前线程的CWinThread指针。
- AfxWinInit函数:由MFC提供的WinMain函数调用,用于初始化应用程序。
3 MFC程序执行流程
MFC程序的执行流程大体为三步“theApp全局对象定义==>TestApp构造函数==>WinMain函数”。在执行theApp对象的构造函数之前先执行CWinApp基类的构造函数,从而把我们自己创建的类和MFC类相关联起来。如图所示。

图3.1 MFC程序执行流程图
3.1 MFC程序执行流程详解
MFC程序将入口函数封装起来了,只留了一个全局对象及构造函数,因此在这里对MFC程序的执行过程进行分析。一个应用程序App就是实例化的程序,而一个应用程序通常会有多个窗口,有主窗口和子窗口,有点主进程先生成主线程,然后由主线程创建其他线程一样,其实本质就是一样的。
(1)全局对象theApp定义
在程序入口函数WinMain加载前,系统先为全局对象theApp分配内存空间,基类CWinApp中的this指针才能指向这个对象。如果没有这个全局对象,则程序在编译时不会出错,但在运行时就会出错。theApp是唯一的应用程序对象。
(2)调用全局对象theApp的构造函数
theApp是子类CtestApp的实例对象,子类继承于CWinApp类,因此会先调用基类的构造函数,再调用子类的构造函数,从而完成应用程序的初始化工作,例如基类中保存theApp的this指针。
(3)进入WinMain函数
WinMain函数在创建工程后自动提供在安装目录中,但是被封装隐藏起来了,WinMain函数会调用AfxWinMain函数获取子类(子类就是继承于CWinApp类的CTestApp类)的this指针,利用此指针调用InitApplication、InitInstance、Run等函数,从而完成窗口类的注册、创建、显示更新,消息循环。这个WinMain函数是在程序编译链接时由链接器将该函数链接到Test程序中的。
(4)进入消息循环
进入消息循环,响应各种消息,直到退出;MFC程序实际上是采用消息映射机制,来完成各种消息的处理,收到WM_QUIT消息时,退出消息循环。MFC程序是靠消息来驱动事件的。
4 MFC消息映射机制
4.1 什么是消息映射机制
Windows 应用程序是靠消息驱动的。在 MFC程序中,界面操作或者线程之间通信都会经常用到消息,通过对消息的处理实现相应的操作。比较典型的过程是,用户操作窗口,然后有消息产生,送给窗口的消息处理函数处理,对用户的操作做出响应。
MFC使用一种消息映射机制来处理消息,在应用程序中的表现就是一个消息与相应的消息处理函数一一对应的消息映射表,以及消息处理函数的声明和实现等代码。当窗口接收到消息时,会到消息映射表中查找该消息对应的消息处理函数,然后由消息处理函数进行相应的处理。
4.2 Windows消息类别
Windows 消息分为系统消息和用户自定义消息。
(1)Windows系统消息
Windows 系统消息有三种。如下所示:
- 标准 Windows 消息:除 WM_COMMAND 外以 WM_开头的消息是标准消息。例如,WM_CREATE、WM_CLOSE。
- 命令消息:消息名为 WM_COMMAND,消息中附带了标识符 ID 来区分是来自哪个菜单、工具栏按钮或加速键的消息。
- 通知消息:通知消息一般由列表框等子窗口发送给父窗口,消息名也是 WM_COMMAND,其中附带了控件通知码来区分控件。
(2)用户自定义消息
用户自定义消息是实际上就是用户定义一个宏作为消息,此宏的值应该大于等于 WM_USER,然后此宏就可以跟系统消息一样使用,窗口类中可以定义它的处理函数。
4.3 MFC消息循环
MFC程序一个很重要的一点就是消息映射机制和消息循环,消息映射表中每一个消息对应着一个消息处理函数,消息循环就是不断的捕捉产生的消息,根据捕捉到的消息去消息映射表中找到对应的消息处理函数执行。MFC消息循环分两种,一种是非对话框程序的消息循环,一种是对话框程序的消息循环。
(1)非对话框程序的消息循环
非对话框程序运行时进入消息循环时的流程。
|
_tWinMain->AfxWinMain->AfxWinInit->CWinThread::InitApplication->CWinThread::InitInstance->CWinThread::Run |
非对话框程序的消息循环是从 CWinThread::Run()开始。
(2)对话框程序的消息循环
对话框程序运行时进入消息循环时的流程。
|
_tWinMain->AfxWinMain->AfxWinInit->CWinThread::InitApplication->CWinThread::InitInstance->dlg-> dlg.DoModal |
(3)总结
非对话框MFC程序的消息循环发生在CWinThread::Run()中,而对话框MFC程序的消息循环则发生在DoModal()中。(非对话框MFC程序的消息是与窗口交换的,而对话框MFC程序的消息则是与对话框进行交互的)
5 MFC窗口框架与控件之间的函数API
5.1 窗口显示
(1)DoModal()函数
弹出模态对话框,有阻塞(效果是弹出对话框后会停留在这个界面)。
5.2数据交换函数
(1)DoDataExchange()函数
DoDataExchange()函数用于窗口框架与控件之间的数据交换,其中的DDX函数用来将两者动态绑定。UpdateData()函数内部调用DoDataExchange()函数进行数据交换。UpdateData(FALSE)是将变量的值传到控件,UpdateData(TRUE)是从控件中取值到关联的变量。
(2)OnSysCommand()函数
这个函数响应系统控制菜单的命令.(即左上角图标处:关闭、最大化、最小化等)。在WM_SYSCOMMAND消息中,nID参数的低四位被Windows内部使用。当应用程序测试nID的值时,它必须用位与操作符AND将值0xFFF0与nID的值组合在一起以获得正确的结果。
(3)OnPaint()函数
当Windows或应用程序请求重画应用程序窗口的一部分时,框架调用这个成员函数。
(4)OnQueryDragIcon()函数
可以在此函数中设置,鼠标显示的样式。系统调用这个函数以在用户拖拉最小化窗口的时候显示光标。如果应用程序返回图标或光标的句柄,系统将它转换为黑与白。如果应用程序返回一个句柄,则这个句柄必须标识与显示设备分辨率相兼容的单色光标或图标。应用程序可以调用CWinApp::LoadCursor或CWinApp::LoadIcon成员函数以从它的可执行文件的资源中载入光标或图。
(5)OnInitDialog()函数
调用这个成员函数是对WM_INITDIALOG消息作出的反应。这条消息是在对话框即将显示之前,在Create,CreateIndirect或DoModal调用期间发出的。
- 首先添加菜单项,再将IDM_ABOUTBOX的选项添加到菜单选项中,使得用户点击选项后可以弹出about对话框,IDM_ABOUTBOX为资源文件中的字符串表中的ID。
- GetSystemMenu(FALSE);用于获取当前的菜单,返回菜单的指针;
- AppendMenu(MF_SEPARATOR);在当前菜单下添加一分隔符;
- AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);添加ID为IDM_ABOUTBOX的菜单选项,显示的选项文字为strAboutMenu;
- SetIcon(m_hIcon, TRUE); m_hIcon在CDialog中定义,该语句设定32*32大小的图标,设定about对话框的图标。
参考博客:https://blog.csdn.net/xiaolongwang2010/article/details/9843077
参考博客:MFC基本框架结构_saimeide mfc-CSDN博客
参考博客:鸡啄米
本文详细介绍了1C++MFC库中的类结构层次,包括MFC应用程序的类型、C++类的继承关系、主要类的种类与功能,以及MFC程序的执行流程、消息映射机制和窗口框架与控件间的函数API。
8169

被折叠的 条评论
为什么被折叠?



