Presentation is loading. Please wait.

Presentation is loading. Please wait.

第4章 MFC编程 4.1 MFC概述 4.2 MFC和Win CObject类 4.4 消息映射的实现

Similar presentations


Presentation on theme: "第4章 MFC编程 4.1 MFC概述 4.2 MFC和Win CObject类 4.4 消息映射的实现"— Presentation transcript:

1 第4章 MFC编程 4.1 MFC概述 4.2 MFC和Win32 4.3 CObject类 4.4 消息映射的实现
4.6 应用程序的退出 1

2 MFC编程 MFC类库是C++类库,构成了MFC编程框架。这些类分别封装了Win32应用程序编程接口、应用程序的概念、OLE特性,以及ODBC和DAO数据访问功能。 OLE------Object Linking and Embedding(对象链接与嵌入)一种面向对象的技术,可以开发重复使用的软组件。 ODBC------Open Database Connectivity(开放数据库连接),是为解决异构数据库间的数据共享而产生的,是基于Windows环境的对数据库访问的一种接口标准。 DAO------Data Access Object(数据访问对象), 是一个面向对象的数据库接口,Microsoft Jet 数据库引擎。 MFC对象与Windows对象有不可分割的关系。Windows对象是Win32下用句柄表示的Windows操作系统对象;MFC对象是C++对象,是一个C++类的实例。两者有很大的区别,但联系紧密。

3 4.1 MFC概述 MFC是一个编程框架 P85 MFC应用程序框架,简称MFC框架,是由MFC(Microsoft Foundation Class Library)中的各种类结合起来构成的。MFC框架从总体上定义了应用程序的轮廓,并提供了用户接口的标准实现方法,程序员只须通过预定义的接口把具体应用程序特有的东西填入这个轮廓,就能建立Windows下的应用程序。

4 MFC是一个编程框架 Microsoft Visual C++提供了相应的工具来完成这个工作:用应用程序向导(AppWizard)可以生成应用程序的骨架文件(代码和资源等);用资源编辑器可以直观地设计用户接口;用类向导(ClassWizard)可以将代码添加到骨架文件;用编译器可以通过类库实现应用程序特定的逻辑。MFC实现了对应用程序概念的封装,把类、类的继承、动态约束、类的关系和相互作用等封装起来。

5 4.1.1 MFC是一个编程框架 1.MFC类库封装的内容 P86 MFC类库是C++类库,构成了MFC框架。
(1) 对Win32应用程序编程接口的封装 MFC将每一个Windows对象封装成一个相应的C++ 对象。 (2) 对应用程序概念的封装 使用SDK编写Windows应用程序时,总要定义窗口过程,注册Windows Class,创建窗口等等,要做许多处理工作。MFC封装了这些处理,替程序员完成这些工作。

6 4.1.1 MFC是一个编程框架 (3) 对COM/OLE特性的封装
OLE(对象的链接与嵌入)建立在COM(组件对象模型)之上,由于支持OLE的应用程序必须实现一系列的接口(Interface),因而相当繁琐。MFC的OLE类封装了OLE API大量的复杂工作,提供了实现OLE的更高级接口。 (4) 对ODBC功能的封装 MFC封装了ODBC API的大量的复杂的工作,形成了与ODBC之间接口的高级C++类,提供了一种方便的访问数据库的编程模式。

7 4.1.1 MFC是一个编程框架 2.MFC类的继承关系 P86
CObject是MFC的根类,绝大多数MFC类是从它派生的。CObject 实现了一些重要的特性,包括动态类信息、动态创建、对象序列化、对程序调试的支持等等。所有从CObject派生的类都将具备或者可以具备CObject所拥有的特性。

8 MFC是一个编程框架 另一个是CCmdTarget类,它是从CObject派生的。CCmdTarget类通过进一步封装一些属性和方法,提供了消息处理的架构。在MFC中,任何可以处理消息的类都是从CCmdTarget类派生的。 针对每种不同的对象,MFC都设计了一组类对这些对象进行封装,每一组类都有一个基类,从基类派生出众多更具体的类。这些对象包括以下种类:窗口对象,基类是CWnd;应用程序对象,基类是CwinThread;文档对象,基类是Cdocument,等等。程序员可以结合自己的实际,从适当的MFC类中派生出自己的类,实现特定的功能,达到自己的编程目的。

9 4.1.1 MFC是一个编程框架 3.虚拟函数和动态约束 P86
这样,通过虚拟函数和消息映射,MFC类提供了丰富的编程接口。程序员在继承基类的同时,可以把自己实现的虚拟函数和消息处理函数嵌入MFC的编程框架。MFC编程框架将在适当的时候、适当的地方来调用程序的代码。

10 4.1.1 MFC是一个编程框架 4.MFC的开发模板 P87
MFC实现了对应用程序概念的封装,实现了类、类的继承、动态约束、类的关系和相互作用的封装。这样封装的结果是为程序员提供了一套开发模板,罗列在应用程序向导AppWizard中。针对不同的应用和目的,程序员可以采用不同的模板。例如,SDI单文档应用程序模板,MDI多文档应用程序模板,规则DLL应用程序模板,扩展DLL应用程序模板,OLE/ActiveX应用程序模板,等等。这些模板都采用以文档-视图为中心的思想,每个模板都包含一组特定的类。

11 MFC是一个编程框架 总之,MFC封装了Win32 API,OLE API,ODBC API等底层函数的功能,并提供更高一层的接口,简化了Windows编程。同时,MFC支持对底层API的直接调用。这种简化体现在MFC提供了一个Windows应用程序开发模式:MFC框架完成对程序的控制,通过预定义或实现了许多事件和消息处理,来完成大部分编程任务。MFC框架处理大部分事件,不依赖程序员的代码;程序员的代码集中用来处理应用程序特定的事件。

12 典型的MDI应用程序的构成 P87 用AppWizard产生一个没有OLE等支持的MDI工程,工程名叫T。AppWizard会自动创建一系列文件,构成一个应用程序骨架。这些文件分为四类:头文件(.h)、实现文件(.cpp)、资源文件(.rc)、模块定义文件(.def)。 1.构成应用程序的对象 图4.1解释了典型的MDI应用程序的结构,箭头表示信息流向。

13 典型的MDI应用程序的构成 图4.1 一个MDI应用程序的构成

14 CWinApp Cdocument Cview CMDIFrame CMDIChildWnd CTApp CTDoc CTView CMainFrame CChildFrame 派生类 应用程序对象 文档对象 视图对象 主边框窗口对象 文档边框窗口对象 实例化

15 4.1.2 典型的MDI应用程序的构成 (1) 应用程序类CTApp
应用程序类CTApp派生于CWinApp类。基于框架的应用程序必须有且只有一个应用程序对象,它负责应用程序的初始化、运行和结束。 (2) 主边框窗口类CMainFrame 对于MDI应用程序,从CMDIFrameWnd类派生主边框窗口类,主边框窗口的客户子窗口(MDIClient)直接包含文档边框窗口。

16 典型的MDI应用程序的构成 如果是SDI应用程序,从CFrameWnd类派生边框窗口类,边框窗口的客户子窗口(MDIClient)直接包含视窗口。 如果要支持工具条、状态栏,则派生的主边框窗口类还要添加CToolBar和CStatusBar类型的成员变量,并且要在一个OnCreate消息处理函数中初始化这两个控制窗口。 主边框窗口用来管理文档边框窗口、视窗口、工具条、菜单、加速键等,协调半模式状态(如上下文的帮助(SHIFT+F1模式)和打印预览)。

17 4.1.2 典型的MDI应用程序的构成 (3) 文档边框窗口CChildFrame
文档边框窗口类从CMDIChildWnd类派生,MDI应用程序使用文档边框窗口来包含视窗口。 (4) 文档CTDoc 文档类从CDocument类派生,用来管理数据,数据的变化、存取都是通过文档实现的。视窗口通过文档对象来访问和更新数据。

18 4.1.2 典型的MDI应用程序的构成 (5) 视图CTView
视类从CView或它的派生类派生。视和文档联系在一起,在文档和用户之间起中介作用,即视图在屏幕上显示文档的内容,并把用户输入转换成对文档的操作。 (6) 文档模板 文档模板类一般不需要派生。MDI应用程序使用多文档模板类CMultiDocTemplate;SDI应用程序使用单文档模板类CSingleDocTemplate。 应用程序通过文档模板类对象来管理上述对象(应用程序对象、文档对象、主边框窗口对象、文档边框窗口对象、视图对象)的创建。

19 典型的MDI应用程序的构成 2.构成应用程序的对象之间的关系 P88 用图的形式可直观地表示所涉及的MFC类的继承或者派生关系。

20 4.1.2 典型的MDI应用程序的构成 3.构成应用程序的文件 P88
下面,从文件的角度来考察AppWizard生成了哪些源码文件,这些文件的作用是什么。 表4.1列出了AppWizard所生成的头文件, 表4.2列出了了AppWizard所生成的实现文件及其对头文件的包含关系。

21 4.1.2 典型的MDI应用程序的构成 APPWizard生成的实现文件 APPWizard生成的头文件
stdafx.cpp 产生预编译的类型信息 t.cpp 定义CTApp的实现 childfrm.cpp 实现了类CChildFrame mainfrm.cpp 实现了类CMainFrame tdoc.cpp 实现了类CTDoc tview.cpp 实现了CTView stdafx.h 标准AFX头文件 resource.h 定义了各种资源 t.h 定义了从CWinApp派生的应用 程序对象CTApp childfrm.h 定义了从 CMDIChildWnd派生的文档 框架窗口对象CTChildFrame mainfrm.h 定义了从 CMDIFrameWnd派生的框 架窗口对象CMainFrame tdoc.h 定义了从Cdocument派 生的文档对象CTDoc tview.h 定义了从Cview派生的 视图对象CTView

22 4.2 MFC和Win32 4.2.1 MFC对象和Windows对象的关系 P89
MFC中最重要的封装是对Win32 API的封装,因此,理解Windows 对象和MFC对象之间的关系是理解MFC的一个关键。所谓Windows对象是Win32下用句柄表示的Windows操作系统对象;所谓MFC对象是C++对象,是一个C++类的实例。两者有很大的区别,但联系紧密。

23 4.2.1 MFC对象和Windows对象的关系 以窗口对象为例:
一个MFC窗口对象是一个C++ CWnd类的实例,是程序直接创建的。在程序执行过程中随着窗口类构造函数的调用而生成,随着析构函数的调用而消失。 Windows的窗口对象是Windows操作系统内部的一个数据结构的实例,由一个“窗口句柄”标识, Windows操作系统创建它并给它分配系统资源。 在创建MFC窗口对象之后,必须调用CWnd类的Create成员函数来创建底层的Windows窗口句柄,并将“窗口句柄”保存在MFC窗口对象的m_bWnd成员变量中。

24 图4.3 MFC的CWnd类窗口对象和Windows的窗口对象的关系
MFC对象和Windows对象的关系 以窗口对象为例: 图4.3 MFC的CWnd类窗口对象和Windows的窗口对象的关系

25 4.2.1 MFC对象和Windows对象的关系 可以从多个方面对MFC对象和Windows对象进行比较。 (1)对应的数据结构不同
(2)所处的层次不同 (3)创建的机制不同 (4)二者转换的方式不同 (5)使用的范围不同 (6)销毁的方法不同 每一种Windows对象都有对应的MFC对象,表4.2列出它们之间的对应关系。

26 4.2.1 MFC对象和Windows对象的关系 (1)对应的数据结构不同
MFC对象是相应C++类的实例,这些类是由MFC或者程序员定义的;Windows对象是Windows系统的内部结构的实例,通过一个句柄来引用;MFC给这些类定义了一个成员变量来保存MFC对象对应的Windows对象的句柄。 (2)所处的层次不同 MFC对象是高层的,Windows对象是低层的。MFC对象不仅把指向相应Windows对象的句柄封装成自己的成员变量(句柄实例变量),还把借助该句柄(HANDLE)来操作Windows对象的Win32 API函数封装为MFC对象的成员函数。站在高层,通过MFC对象去操作低层的Windows对象,只须直接引用成员函数。

27 4.2.1 MFC对象和Windows对象的关系 (3)创建的机制不同
MFC对象是由程序通过调用类的构造函数直接创建的;Windows对象是由相应的SDK函数创建的。创建的过程也不同 。 (4)二者转换的方式不同 使用MFC对象的成员函数GetSafeHandle,可以从一个MFC对象得到对应的Windows对象的句柄。使用MFC对象的成员函数Attach或者FromHandle,可以从一个已存在的Windows对象创建一个对应的MFC对象,前者得到一个永久性对象,后者得到的可能是一个临时对象。

28 4.2.1 MFC对象和Windows对象的关系 (5)使用的范围不同
MFC对象只服务于创建它的进程,对系统的其他进程来说是不可见、不可用的;而一旦创建了Windows对象,其句柄在整个Windows系统中,是全局可见的。一些句柄可以被其他进程使用。典型的例子是,一个进程可以获得另一进程的窗口句柄,并给该窗口发送消息。 (6)销毁的方法不同 MFC对象随着析构函数的调用而消失;但Windows对象必须由相应的Windows系统函数销毁。

29 MFC对象和Windows对象的对应关系
描述       Windows句柄     MFC对象 CWnd及其派生类 CDC及其派生类 CMenu Cpen及其派生类 CBush及其派生类 CFont及其派生类 CBitmap及其派生类 CPalette及其派生类 CRgn及其派生类 CImageList及其派生类 CSocket及其派生类 窗口 设备上下文 菜单 刷子 字体 位图 调色板 区域 图像列表 套接字 HWND HDC HMENU HPEN HBRUSH HFONT HBITMAP HPALETTE HRGN HIMAGELIST SOCKET

30 4.2 MFC和Win32 4.2.2 几个主要的类 P91 1.Win32 API的窗口对象(Windows Object)
MFC的CWnd类是对Win32 API的窗口对象的封装。 用SDK的Win32 API编写各种Windows应用程序,有其共同的规律:首先是编写WinMain函数,编写处理消息和事件的窗口过程WndProc,在WinMain里头注册窗口(Register Window),创建窗口,然后开始应用程序的消息循环。 一个应用程序在创建某个类型的窗口前,必须首先注册该“窗口类型”(Register Window Class),把窗口过程、窗口风格以及其他信息和要登记的窗口类型关联起来。 几个主要的类 P91

31 几个主要的类 “窗口类型”是Windows系统的数据结构,可以把它理解为Windows系统的类型定义,而窗口对象则是相应“窗口类型”的实例。Windows使用一个结构来描述“窗口类型”,其定义如下: typedef struct _WNDCLASS { UINT cbSize; //该结构的字节数 UINT style; //窗口类型的风格 WNDPROC lpfnWndProc; //窗口过程 int cbClsExtra; int cbWndExtra; HANDLE hInstance; //该窗口类型的窗口过程所属的应用实例 HICON hIcon; //该窗口类型所用的像标 HCURSOR hCursor; //该窗口类型所用的光标 HBRUSH hbrBackground; //该窗口类型所用的背景刷 LPCTSTR lpszMenuName; //该窗口类型所用的菜单资源 LPCTSTR lpszClassName;//该窗口类型的名称 HICON hIconSm; //该窗口类型所用的小像标 } WNDCLASS;

32 几个主要的类 2.MFC的窗口类CWnd P92 在Windows系统里,一个窗口的属性分两个地方存放:一部分放在“窗口类型”里头,如上所述的在注册窗口时指定;另一部分放在窗口对象本身,如:窗口的尺寸,窗口的位置(X,Y轴),窗口的Z轴顺序,窗口的状态(ACTIVE,MINIMIZED,MAXMIZED,RESTORED…),和其他窗口的关系(父窗口,子窗口…),窗口是否可以接收键盘或鼠标消息,等等。 为了表达所有这些窗口的共性,MFC设计了一个窗口基类CWnd。有一点非常重要,那就是CWnd提供了一个标准而通用的MFC窗口过程,MFC下所有的窗口都使用这个窗口过程。利用MFC消息映射机制,是这个通用的窗口过程能为各种窗口实现不同的操作。

33 几个主要的类 CWnd类提供了一系列成员函数。它们或者是对Win32相关函数的封装,或者是CWnd新设计的一些函数。主要有: (1)窗口创建函数Create。函数Create封装了Win32窗口创建函数::CreatWindowEX。 (2)窗口销毁函数 DestroyWindow,销毁窗口后调用的函数PostNcDestroy。 (3)用于设定、获取、改变窗口属性的函数,设置窗口标题SetWindowText,得到窗口标题函数GetWindowText,设置窗口图标函数SetIcon,得到窗口图标函数GetIcon。 (4)用于完成窗口动作的函数。

34 4.2.2 几个主要的类 3.在MFC下创建一个窗口对象 P93
几个主要的类 3.在MFC下创建一个窗口对象 P93 MFC下创建一个窗口对象分两步,首先创建MFC窗口对象,然后创建对应的Windows窗口对象。在内存使用上,MFC窗口对象可以在栈或者堆(使用new创建)中创建。具体表述如下: ①创建MFC窗口对象。通过定义一个CWnd或其派生类的实例变量或者动态创建一个MFC窗口的实例,前者在栈空间创建一个MFC窗口对象,后者在堆空间创建一个MFC窗口对象。 ②调用相应的窗口创建函数,创建Windows窗口对象。

35 4.2.2 几个主要的类 4.MFC窗口的使用 P94 MFC提供了大量的窗口类,其功能和用途各异。程序员应该如何选择和使用他们呢?
几个主要的类 4.MFC窗口的使用 P94 MFC提供了大量的窗口类,其功能和用途各异。程序员应该如何选择和使用他们呢? 直接使用MFC提供的窗口类,或者先从MFC窗口类派生一个新的C++类,然后使用它,这些在通常情况下都不需要程序员提供窗口注册的代码。是否需要派生新的C++类,视MFC已有的窗口类是否能满足使用要求而定。派生的C++类继承了基类的特性并改变或扩展了它的功能,例如增加或者改变对消息、事件的特殊处理等。

36 几个主要的类 5.在MFC下窗口的销毁 P95 窗口对象使用完毕,应该销毁。在MFC下,一个窗口对象的销毁包括HWND窗口对象的销毁和MFC窗口对象的销毁。一般情况下,MFC编程框架自动地处理了这些。 (1)对于CFrameWnd和Cview的派生类,调用DestroyWindow函数关闭和销毁窗口。 (2)对于Windows Control窗口,在它们的析构函数中调用DestroyWindow函数来销毁窗口。随着析构函数的调用,MFC窗口对象和它的Windows对象都被销毁。

37 4.3 CObject类 P95 CObject是大多数MFC类的根类或基类。CObject类有很多有用的特性:对运行时类信息的支持,对动态创建的支持,对串行化的支持,对象诊断输出,等等。MFC从CObject派生出许多类,这些派生类具备CObject特性中的一个或者多个特性。程序员也可以从CObject类派生出自己的类,利用CObject类的这些特性。

38 4.3 CObject类 4.3.1 CObject类的定义 P95
CObject定义了一个CRuntimeClass类型的静态成员变量 ,还定义了几组函数:构造函数和析构函数类;诊断函数;与运行时类信息相关的函数;与串行化相关的函数 。 其中,一个静态函数: _GetBaseClass;五个虚拟函数:析构函数、GetRuntimeClass、Serialize、AssertValid、Dump。这些虚拟函数,在CObject的派生类中应该有更具体的实现。必要的话,派生类实现它们时可能要求先调用基类的实现。 静态成员变量 classCObject和相关函数实现了对CObjet特性的支持。 CObject类的定义 P95

39 4.3 CObject类 4.3.2 CObject类的特性 P96 下面对三种特性分别描述 1.对运行时类信息的支持
该特性用于在运行时确定一个对象是否属于一特定类(是该类的实例),或者从一个特定类派生来的,CObject提供IsKindOf函数来实现这个功能。 从CObject派生的类要具有这样的特性,需要: (1)定义该类时,在类说明中使用 DECLARE_DYNAMIC(CLASSNMAE)宏; (2)在类的实现文件中使用 IMPLEMENT_DYNAMIC(CLASSNAME,BASECLASS)宏。

40 4.3.2 CObject类的特性 2.对动态创建的支持 P97
前面提到了动态创建的概念,就是运行时创建指定类的实例。在MFC中大量使用,如前所述框架窗口对象、视对象,还有文档对象都需要由文档模板类(CDocTemplate)对象来动态的创建。 从CObject派生的类要具有动态创建的功能,需要: (1)定义该类时,在类说明中使用DECLARE_DYNCREATE(CLASSNMAE)宏; (2)定义一个不带参数的构造函数(默认构造函数); (3)在类的实现文件中使用IMPLEMENT_DYNCREATE(CLASSNAME,BASECLASS)宏; (4)使用时先通过宏RUNTIME_CLASS得到类的RunTime信息,然后使用CRuntimeClass的成员函数CreateObject创建一个该类的实例。

41 4.3.2 CObject类的特性 3.对序列化的支持 P97
(1)定义该类时,在类说明中使用DECLARE_SERIAL(CLASSNMAE)宏; (2)定义一个不带参数的构造函数(默认构造函数); (3)在类的实现文件中使用IMPLEMENT_SERIAL(CLASSNAME,BASECLASS)宏; (4)覆盖Serialize成员函数。(如果直接调用Serialize函数进行序列化读写,可以省略前面三步。)

42 CObject类的特性 对运行时类信息的支持、动态创建的支持、串行化的支持层(不包括直接调用Serailize实现序列化),这三种功能的层次依次升高。如果对后面的功能支持,必定对前面的功能支持。支持动态创建的话,必定支持运行时类信息;支持序列化,必定支持前面的两个功能,因为它们的声明和实现都是后者包含前者。

43 4.4 消息映射的实现 P98 Windows系统将Windows应用程序的输入事件转换为消息,并将消息发送给应用程序的窗口。这些窗口通过窗口过程来接收和处理消息,然后把控制返还给Windows。 1.消息的分类 可以从消息的发送途径和消息的来源两方面对消息分类: (1)队列消息和非队列消息 从消息的发送途径上,可将消息分为队列消息和非队列消息。队列消息送到系统消息队列,然后送到线程消息队列;非队列消息直接送给目的窗口过程。 Windows系统维护着一个系统消息队列(System message queue),每个GUI线程有一个线程消息队列(Thread message queue)。

44 4.4 消息映射的实现 (2)系统消息和应用程序消息 从消息的来源,可将消息分为系统定义的消息和应用程序定义的消息。
4.4 消息映射的实现 (2)系统消息和应用程序消息 从消息的来源,可将消息分为系统定义的消息和应用程序定义的消息。 系统消息ID的范围是从0到WM_USER-1,或从0x80000到0xBFFFF;应用程序消息ID的范围是从WM_USER(0x0400)到0x7FFF,或从0xC000到0xFFFF;WM_USER到0x7FFF范围的消息由应用程序自己使用;0xC000到0xFFFF范围的消息用来和其他应用程序通信,为了保证ID的唯一性,可使用::RegisterWindowMessage来得到该范围的消息ID。

45 4.4 消息映射的实现 2.MSG消息结构和消息处理 P99 (1)MSG消息结构
4.4 消息映射的实现 2.MSG消息结构和消息处理 P99 (1)MSG消息结构 为了从消息队列获取消息信息,可以调用一些函数,例如,使用::GetMessage函数可从消息队列得到并从队列中移走消息,使用::PeekMessage函数可从消息队列得到消息但不移走。这些函数都需要使用MSG消息结构来保存获得的消息信息。MSG结构包括了六个成员,用来描述消息的有关属性。它的定义是: typedef struct tagMSG { // msg 结构 HWND hwnd; // 接收消息的窗口句柄 UINT message; // 消息标识( ID) WPARAM wParam; // 第一个消息参数 LPARAM lParam; // 第二个消息参数 DWORD time; // 消息产生的时间 POINT pt; // 消息产生时鼠标的位置 } MSG;

46 4.4 消息映射的实现 (2)应用程序通过窗口过程来处理消息
4.4 消息映射的实现 (2)应用程序通过窗口过程来处理消息 直接使用Win32 API编程时,每个“窗口类”都要登记一个如下形式的窗口过程: LRESULT CALLBACK MainWndProc ( HWND hwnd, // 窗口句柄 (a window handle) UINT msg, // 消息标识 (a message identifier) WPARAM wParam, // 32位的消息参数1 LPARAM lParam // 32位的消息参数2 ) 应用程序通过窗口过程来处理消息:非队列消息由Windows直接送给目的窗口的窗口过程,队列消息由Windows调用::DispatchMessage派发给目的窗口的窗口过程。窗口过程被调用时,接受上述的四个参数。如果需要,窗口过程可以调用::GetMessageTime获取消息产生的时间,调用::GetMessagePos获取消息产生时鼠标光标所在的位置。

47 4.4 消息映射的实现 (3)应用程序通过消息循环来获得对消息的处理
4.4 消息映射的实现 (3)应用程序通过消息循环来获得对消息的处理 直接使用Win32 API编程时,每个GDI应用程序在主窗口创建之后,都应进入消息循环,接受用户输入,解释和处理消息。消息循环的结构如下: // 从消息队列得到消息 while (GetMessage(&msg, (HWND) NULL, 0, 0)) { if (hwndDlgModeless == (HWND) NULL || !IsDialogMessage(hwndDlgModeless, &msg) && !TranslateAccelerator(hwndMain, haccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); // 发送消息 } }

48 4.4 消息映射的实现 3.MFC消息处理 P100 所谓消息映射,就是让程序员指定用来处理某个消息的某个MFC类。使用MFC提供的ClassWizard类向导,可以在处理消息的类中添加处理消息的成员函数,方便地实现消息映射。在此基础上,程序员可将自己的代码添加到这些消息处理函数中,实现所希望的消息处理。 如果派生类要覆盖基类的消息处理函数,就用ClassWizard在派生类中添加一个消息映射条目,用同样的原型定义一个函数,然后实现该函数。这个函数覆盖派生类的任何基类的同名处理函数。

49 4.4 消息映射的实现 4.MFC消息映射的定义和实现 现在来介绍MFC的消息机制的实现原理和消息处理的过程。 (1)MFC处理的三类消息
4.4 消息映射的实现 4.MFC消息映射的定义和实现 现在来介绍MFC的消息机制的实现原理和消息处理的过程。 (1)MFC处理的三类消息 MFC主要处理三类消息,他们对应的处理函数和处理过程有所不同: ①Windows消息,是消息名以前缀 “WM_”打头的消息,但WM_COMMAND消息除外。Windows消息直接被送给MFC的窗口过程处理,窗口过程再调用对应的消息处理函数。这类消息一般由窗口对象来处理,也就是说,这类消息处理函数一般是MFC窗口类的成员函数。

50 4.4 消息映射的实现 ②控制通知消息,是控制子窗口送给父窗口的WM_COMMAND通知消息。窗口过程调用对应的消息处理函数。这类消息一般也由窗口对象来处理,对应的消息处理函数一般也是MFC窗口类的成员函数。 ③命令消息,这是来自菜单、工具条按钮、加速键等用户接口对象的WM_COMMAND通知消息,属于应用程序自己定义的消息。通过消息映射机制,MFC框架把命令按一定的路径分发给多种类型的具备消息处理能力的对象来处理,如文档、窗口、应用程序、文档模板等对象。能处理消息映射的类必须从CCmdTarget类派生。

51 4.4 消息映射的实现 (2)MFC消息映射的实现方法
4.4 消息映射的实现 (2)MFC消息映射的实现方法 程序员可以使用MFC的类向导ClassWizard来实现消息映射。类向导在源码中添加一些消息映射的内容,并声明和实现消息处理函数。 (3)消息映射宏的种类 ①用于映射 Windows消息的宏,前缀为“ON_WM_”。 ②用于映射命令消息的宏ON_COMMAND ③用于控制通知消息的宏 ④用于用户界面接口状态更新的 ON_UPDATE_COMMAND_UI宏 ⑤用于其他消息的宏 ⑥扩展消息映射宏

52 4.5 MFC对象的创建 4.5.1 MFC对象的关系 P102 1.创建关系
下图大略地表示了创建顺序,但表4.4更直接地显示了创建与被创建的关系。

53 MFC对象的关系 2.交互作用关系 P102 应用程序对象有一个文档模板列表,存放一个或多个文档模板对象;文档模板对象有一个打开文档列表,存放一个或多个已经打开的文档对象;文档对象有一个视列表,存放显示该文档数据的一个或多个视对象;还有一个指针指向创建该文档的文档模板对象;视有一个指向其关联文档的指针,视是一个子窗口,其父窗口是边框窗口(或者文档边框窗口);文档边框窗口有一个指向其当前活动视的指针;文档边框窗口是边框窗口的子窗口。 Windows管理所有已经打开的窗口,把消息或事件发送给目标窗口。通常,命令消息发送给主边框窗口。

54 MFC对象的关系 图4.5 构成一个应用程序的对象

55 4.5 MFC对象的创建 MFC提供的接口 P104 MFC编程就是把一些应用程序特有的东西填入MFC框架。MFC提供了两种填入的方法:一种就是使用上节论述的消息映射,消息映射给应用程序的各种对象处理各种消息的机会;另一种就是使用虚拟函数,MFC在实现许多功能或者处理消息、事件的过程中,调用了虚拟函数来完成一些任务,这样就给了派生类覆盖这些虚拟函数实现特定处理的机会。

56 MFC提供的接口 1.虚拟函数接口 几乎每一个MFC类都定义和使用了虚拟成员函数,程序员可以在派生类中覆盖它们。一般,MFC提供了这些函数的缺省实现,所以覆盖函数应该调用基类的实现。由于基类的虚拟函数被派生类继承,所以在派生类中不作重复说明。覆盖基类的虚拟函数可以通过ClassWizard进行,不过,并非所有的函数都可以这样,有的必须手工加入函数声明和实现。

57 4.5.2 MFC提供的接口 2.消息映射方法和标准命令消息
窗口对象可以响应以“WM_”为前缀的标准Windows消息,消息处理函数名称以“ON”为前缀。不同类型的Windows窗口处理的Windows消息是有所不同的,因此,不同类型的MFC窗口实现的消息处理函数也有所不同。例如,多文档边框窗口能处理WM_MDIACTIVATE消息,其他类型窗口就不能。程序员从一定的MFC窗口派生自己的窗口类,对感兴趣的消息,覆盖基类的消息处理函数,实现自己的消息处理函数。

58 4.5 MFC对象的创建 MFC对象的创建过程    P104 MFC应用程序的执行分为三个阶段:应用程序启动和初始化阶段,与用户交互阶段,程序退出和清理阶段。MFC应用程序通过MFC的接口填入MFC框架的自己的特殊处理,可能在这三个阶段被MFC框架调用。 在这3个阶段中,与用户交互阶段是各个程序自己的事,一般都不一样,涉及比较多的程序员编写的代码。但是程序的启动和退出两个阶段是MFC框架所实现的,是MFC框架的一部分,有同样的步骤和规则。 MFC程序启动和初始化过程就是创建MFC对象和Windows对象,建立各对象之间的关系并把窗口显示在屏幕上。退出过程就是关闭窗口,销毁所创建MFC对象和Windows对象。

59 4.6 应用程序的退出 P107 一般Windows应用程序启动后就进入消息循环,等待或处理用户的输入,如果用户按了主窗口的关闭按钮,或者选择执行系统菜单的“关闭”项,或者从“文件”菜单选择执行“退出”,都会导致应用程序主窗口被关闭。主窗口关闭了,应用程序也随之退出。 下面以用户单击主窗口的“关闭”按钮为例,说明应用程序退出的过程。 (1)用户单击主窗口的“关闭”按钮,导致发送MFC标准命令ID_APP_EXIT。MFC调用CWinApp::OnAppExit( )来完成对该命令消息的缺省处理,主要是向主窗口发送WM_CLOSE消息。

60 4.6 应用程序的退出 (2)主窗口处理WM_CLOSE消息。MFC提供了CFrameWnd::OnClose函数来处理各类边框窗口的关闭。当主窗口接到WM_CLOSE消息后,自动调用OnClose( )函数来处理窗口的关闭。关闭窗口后,发送WM_QUIT消息。 (3)收到WM_QUIT消息后,退出消息循环,进而退出整个应用程序。


Download ppt "第4章 MFC编程 4.1 MFC概述 4.2 MFC和Win CObject类 4.4 消息映射的实现"

Similar presentations


Ads by Google