32
3 3 MFC MFC 第第第第第第 第第第第第第 3.1 3.1 第第第第第第第第第第第 第第第第第第第第第第第 MFC MFC 第 3.2 3.2 第第第第 第第第第 MFC MFC 第第第第 第第第第 3.3 3.3 第第第第第第第 第第第第第第第 / 第第第第 第第第第 3.4 3.4 第第第 第第第 CDocument CDocument 第第第第 第第第第 3.5 3.5 第第第 第第第 CView CView 第第第第 第第第第 3.6 3.6 第第第第第 第第第第第 CFrameWnd CFrameWnd 第第第第 第第第第 3.7 3.7 第第第第第 第第第第第 CDocTemplate CDocTemplate 3.8 3.8 第第第第第第第第第 第第第第第第第第第 3.9 MFC 3.9 MFC 第第 第第 / 第第第第第第第第第第第第第第第第 第第第第第第第第第第第第第第第第 3.10 3.10 第第第第第第第 第第第第第第第

第 3 章 MFC 应用程序框架

Embed Size (px)

DESCRIPTION

第 3 章 MFC 应用程序框架. 3.1 早期的应用程序框架及其 MFC 类 3.2 最简单的 MFC 程序实例 3.3 应用程序的文档 / 视图结构 3.4 文档类 CDocument 的派生类 3.5 视图类 CView 的派生类 3.6 窗口框架类 CFrameWnd 的派生类 3.7 文档模板类 CDocTemplate 3.8 应用程序类的派生类 3.9 MFC 文档 / 视图应用程序框架中各个对象的关系 3.10 对象的动态组建. 本章主要内容:. MFC 的基本应用程序框架类 Windows 应用程序的文档/视图结构 - PowerPoint PPT Presentation

Citation preview

Page 1: 第 3 章  MFC 应用程序框架

第第 33 章 章 MFCMFC 应用程序框架应用程序框架

3.1 3.1 早期的应用程序框架及其早期的应用程序框架及其 MFCMFC 类类

3.2 3.2 最简单的最简单的 MFCMFC 程序实例程序实例

3.3 3.3 应用程序的文档应用程序的文档 // 视图结构视图结构

3.4 3.4 文档类文档类 CDocumentCDocument 的派生类的派生类

3.5 3.5 视图类视图类 CViewCView 的派生类的派生类

3.6 3.6 窗口框架类窗口框架类 CFrameWndCFrameWnd 的派生类的派生类

3.7 3.7 文档模板类文档模板类 CDocTemplateCDocTemplate

3.8 3.8 应用程序类的派生类应用程序类的派生类

3.9 MFC3.9 MFC 文档文档 // 视图应用程序框架中各个对象的关系视图应用程序框架中各个对象的关系

3.10 3.10 对象的动态组建对象的动态组建

Page 2: 第 3 章  MFC 应用程序框架

本章主要内容: • MFC 的基本应用程序框架类 • Windows 应用程序的文档/视图结构 • 文挡 / 视图结构的应用程序框架类 • 对象的动态创建

Page 3: 第 3 章  MFC 应用程序框架

3.1 早期的应用程序框架及其 MFC 类1. 早期的应用程序框架

与例与例 2-32-3 非常相非常相似似

与例与例 2-32-3 非常相非常相似似

Page 4: 第 3 章  MFC 应用程序框架

3.1 早期的应用程序框架及其 MFC 类2. MFC 的窗口类—— CFrameWnd

CFrameWnd

CWnd

CCmdTarget

CObject

MFC 中相当一部分类的基类 程序诊断功能 对象的动态创建、序列化功能

消息处理能力

提供窗口 消息处理能力

应用程序主窗口 其他子窗口的容器

Page 5: 第 3 章  MFC 应用程序框架

3.1 早期的应用程序框架及其 MFC 类2. MFC 的窗口类—— CFrameWnd

Page 6: 第 3 章  MFC 应用程序框架

3.1 早期的应用程序框架及其 MFC 类3. CWinApp 类

CObject

CCmdTarget

CWinThread

CWinApp

应用程序类在类族中的位置

应用程序类在类族中的位置

WinMain 函数的函数体的封装

支持线程管理

Page 7: 第 3 章  MFC 应用程序框架

3.1 早期的应用程序框架及其 MFC 类3. CWinApp 类

Page 8: 第 3 章  MFC 应用程序框架

3.2 最简单的 MFC 程序实例Type of New Project: MFC App Wizard[exe]

WinMain -> WinMain -> AfxWinMainAfxWinMain

应用程序初始化应用程序初始化

消息循环消息循环

Page 9: 第 3 章  MFC 应用程序框架

3.2 最简单的 MFC 程序实例MFC 如何使用应用程序对象

MFC 应用程序代码没有包含自己定义的类以外的任何可执行代码。例如,它没有 main 或 WinMain 函数。在整个程序中唯一的语句就是具有全局有效性的用来实例化应用程序对象的语句。那么到底是什么启动了程序的运行,应用程序对象又是何时起作用的呢?

揭开这个谜底的最好方法就是看看主框架的源代码,一个 MFC 提供的源代码文件( winmain.cpp )找那个包含了一盒 AfxWinMain函数,它在 MFC 中的作用相当于 WinMain (实际上,当您购买了Visual C++ , 同 时 也 就 得 到 了 MFC 提 供 的 源 代码。) AfxWinMain 广泛使用应用程序对象,这就是为什么应用程序对象必须全局声明的原因。全局变量和对象在任何其他代码执行以前被创建,在 AfxWinMain 运行以前,应用程序对象必须在内存中存在。

运行一开始, AfxWinMain 就调用 AfxWinInit 函数来初始化主框架,并将 hInstance 、 nCmdShow 以及其他 AfxWinMain 函数参数复制给应用程序对象的数据成员,然后它调用 InitApplication和 InitInstance 。然后, AfxWinMain 调用应用程序对象的 Run函数,该函数执行消息循环。

Page 10: 第 3 章  MFC 应用程序框架

3.3 应用程序的文档 / 视图结构

应用程序主窗口

CFrameWnd窗口框架类

CView视图类

CDocument文档类

原因:应用程序主窗口需要管理,1. 窗 口 本 身 的 一 些 事 务 ( max 、 min 、 close 、 menu command

response , etc )2. 程序的数据3. 数据的显示和接受用户区的消息与处理

因此,因此, MFCMFC 把早期的窗口类的功能分解成三个部分:把早期的窗口类的功能分解成三个部分:• 数据存储、管理部分(数据存储、管理部分( CDocumentCDocument ))• 数据显示与用户交互部分(数据显示与用户交互部分( CViewCView ))• 管理窗口框的大小、标题、菜单条、状态条的窗框部分(管理窗口框的大小、标题、菜单条、状态条的窗框部分( CFrameWnCFrameWndd ))

1. 1. 基本概念基本概念

Page 11: 第 3 章  MFC 应用程序框架

3.3 应用程序的文档 / 视图结构

窗体标题窗体标题

CFrameWnd

CView

表示

存储

Cdocument

由 文 档 模 板 类由 文 档 模 板 类CDocTemplateCDocTemplate进 行 统 一 创 建 和进 行 统 一 创 建 和管理管理

1. 1. 基本概念基本概念

Page 12: 第 3 章  MFC 应用程序框架

3.3 应用程序的文档 / 视图结构2. SDI & MDI2. SDI & MDI

SDI (Single Document SDI (Single Document Interface, Interface, 单文档界面单文档界面 ))

MDI (multi-Document MDI (multi-Document Interface, Interface, 多文档界面多文档界面 ))

Page 13: 第 3 章  MFC 应用程序框架

3.4 文档类 CDocument 的派生类

应用程序的文档类由应用程序的文档类由CDocumentCDocument 派生派生

Serialize()Serialize() 函数:函数: 文件操作时响应文件操作时响应 Read data from fileRead data from file Write data to fileWrite data to file

序列化序列化 // 串行化串行化SerializationSerialization

序列化序列化 // 串行化串行化SerializationSerialization

理解理解 P60P60 :例:例 3-23-2

Page 14: 第 3 章  MFC 应用程序框架

3.5 视图类 CView 的派生类为应用程序框架提供用户区,承担用户数据的显示(表现形式,为应用程序框架提供用户区,承担用户数据的显示(表现形式,

图形、文字等),同时替代窗口框架接收外界的输入。因此,图形、文字等),同时替代窗口框架接收外界的输入。因此,该类该类是程序员编码最多的地方是程序员编码最多的地方。。 派生关系派生关系

与文档类的联系与文档类的联系纽带纽带

用户区的绘制,用户区的绘制,注意:谁来触发注意:谁来触发

1)1) 自动重绘自动重绘 ; 2); 2) 手动视图更手动视图更新新

理解理解 P62P62 :例:例 3-33-3

Page 15: 第 3 章  MFC 应用程序框架

OnDraw(CDC * pDC)OnDraw(CDC * pDC)

OnDrawOnDraw

CDCCDC

Class of Context DeviceClass of Context Device

设备环境类设备环境类

画笔、画刷、调色板等画笔、画刷、调色板等

窗口重绘窗口重绘指令(消息)指令(消息) 绘制绘制

画布画布CanvasCanvas

3.5 视图类 CView 的派生类

Page 16: 第 3 章  MFC 应用程序框架

3.6 窗口框架类 CFrameWnd 的派生类

当使用当使用 MFC AppWizardMFC AppWizard 创建应用程序时创建应用程序时 CFrameWndCFrameWnd

CMainFrameCMainFrame

派生派生

C:\Program Files\Microsoft Visual C:\Program Files\Microsoft Visual Studio\VC98\MFC\Include\AfxWin.hStudio\VC98\MFC\Include\AfxWin.h

Page 17: 第 3 章  MFC 应用程序框架

3.7 文档模板类 CDocTemplateCObjectCObject

CCmdTargetCCmdTarget

CDocTemplateCDocTemplate

CSingleDocTemplateCSingleDocTemplate CMultiDocTemplateCMultiDocTemplate

单一的文档指针单一的文档指针

Page 18: 第 3 章  MFC 应用程序框架

3.7 文档模板类 CDocTemplate

文档类链表文档类链表

查阅查阅 CPtrListCPtrList 类类

Page 19: 第 3 章  MFC 应用程序框架

3.8 应用程序类的派生类

RUNTIME_CLASSRUNTIME_CLASS 分分别 创 建 了别 创 建 了 docdoc 、、 viewview和窗口框架类的对象和窗口框架类的对象

Page 20: 第 3 章  MFC 应用程序框架

3.8 应用程序类的派生类程序员的主要工作程序员的主要工作 -- 重要的类及其函数成员重要的类及其函数成员

1.1. CWinAppCWinApp 的的 InitInstanceInitInstance 的重新定义的重新定义

2.2. CDocumentCDocument 中程序数据的管理中程序数据的管理

3.3. 在在 CViewCView 中获取中获取 CDocumentCDocument 的指针,并能访问程序数据的指针,并能访问程序数据

4.4. CViewCView 的的 OnDrawOnDraw 函数编写数据的显示代码函数编写数据的显示代码

5.5. 实现各个必要的消息映射表实现各个必要的消息映射表

Page 21: 第 3 章  MFC 应用程序框架

3.9 MFC3.9 MFC 文档文档 // 视图应用程序框架中各个对象的关系视图应用程序框架中各个对象的关系

CWinApp theAppCWinApp theApp ;;

theApp.InitInstancetheApp.InitInstance系统系统

应用程序对象

文档模板

文档对象文档对象窗口框架对象窗口框架对象

视图对象视图对象

11 )应用程序各对象的创建顺序)应用程序各对象的创建顺序

Page 22: 第 3 章  MFC 应用程序框架

3.9 MFC 文档 / 视图应用程序框架中各个对象的关系

22 )应用程序各对象之间)应用程序各对象之间

(自学)(自学)

Page 23: 第 3 章  MFC 应用程序框架

3.10 对象的动态创建

WHYWHY ??

程序运行时,动态地从已知(已定义)的类中创建某一类程序运行时,动态地从已知(已定义)的类中创建某一类的对象。创建时类的类型(不同的文档等)、个数是不确定的的对象。创建时类的类型(不同的文档等)、个数是不确定的(动态地)。(动态地)。

HOWHOW ??

11 )对象的创建离不开其构造函数。所以只有正确地调用类)对象的创建离不开其构造函数。所以只有正确地调用类的构造函数,便能正确地创建该类的对象。的构造函数,便能正确地创建该类的对象。

22 )建立正确的类名及其构造函数的对应关系。借助这种对)建立正确的类名及其构造函数的对应关系。借助这种对应关系表,便可以在传递类名时,创建该类的对象。应关系表,便可以在传递类名时,创建该类的对象。

如,如, CObject * CreateObject() { return new CMyWnd; }CObject * CreateObject() { return new CMyWnd; }

1) 1) 问题的提出和解决问题的提出和解决

Page 24: 第 3 章  MFC 应用程序框架

3.10 对象的动态创建

CMyDocCMyDoc

m_pfnCreateObjectm_pfnCreateObject

CMyWndCMyWnd

m_pfnCreateObjectm_pfnCreateObject

…………

CMyViewCMyView

m_pfnCreateObjectm_pfnCreateObject

CreateObject()CreateObject()

CreateObject()CreateObject()

CreateObject()CreateObject()

类名类名函数指针函数指针

类名类名函数指针函数指针

类名类名函数指针函数指针

return new CMyDoc;return new CMyDoc;

return new CMyWnd;return new CMyWnd;

return new CMyView;return new CMyView;

CMyDocCMyDoc

CMyWndCMyWnd

CMyViewCMyView

关系维护关系维护

类与对象创建函数映射表类与对象创建函数映射表

Page 25: 第 3 章  MFC 应用程序框架

3.10 对象的动态创建2) 2) 类信息表及其声明和实现类信息表及其声明和实现

类信息表:用于动态创建类对象所需的信息。类信息表:用于动态创建类对象所需的信息。 CRuntimeClassCRuntimeClass 结结构体。构体。

链接类信息表链接类信息表链接类信息表链接类信息表 链接类族信息链接类族信息链接类族信息链接类族信息

Page 26: 第 3 章  MFC 应用程序框架

3.10 对象的动态创建2) 2) 类信息表及其声明和实现类信息表及其声明和实现

class1

类的信息

m_pNextClass

class2

类的信息

m_pNextClass

classN

类的信息

m_pNextClass

…… ……

NULLNULL

类信息链表的结构类信息链表的结构

相关的宏相关的宏classN

类的信息

m_pNextClass

class A : public B {class A : public B {public:public: DECLARE_DYNCREATE(A)DECLARE_DYNCREATE(A)……};};

IMPLEMENT_DYNCREATE(A, B)IMPLEMENT_DYNCREATE(A, B)m_pBaseClassm_pBaseClass

Page 27: 第 3 章  MFC 应用程序框架

3.10 对象的动态创建3) 3) 对象类信息表的提取对象类信息表的提取

RUNTIME_CLASSRUNTIME_CLASS 宏宏 #define RUNTIME_CLASS(class_name) \#define RUNTIME_CLASS(class_name) \

((CRuntimeClass *)(&class_name::class##class_name))((CRuntimeClass *)(&class_name::class##class_name))

Remarks Use this macro to get the run-time class structure from the name of a C++

class.

RUNTIME_CLASS returns a pointer to a CRuntimeClass structure for the

class specified by class_name. Only CObject-derived classes declared with

DECLARE_DYNAMIC, DECLARE_DYNCREATE, or DECLARE_SERIAL will

return pointers to a CRuntimeClass structure.

Example// example for RUNTIME_CLASS

CRuntimeClass* ptr = RUNTIME_CLASS( CAge );

ASSERT( lstrcmp( ptr->m_lpszClassName, "CAge" )  == 0 );

续行符续行符 连接符连接符

Page 28: 第 3 章  MFC 应用程序框架

进一步理解进一步理解 RUNTIME_CLASSRUNTIME_CLASS

DYNAMIC 支持在 CObject 派生类中,可以获得动态 " 验证 " 支持,访问运行时类

信息方法: 声明时添加宏: DECLARE_DYNAMIC( class_name )实现时添加宏 : IMPLEMENT_DYNAMIC

DECLARE_DYNAMIC(class_name)DECLARE_DYNAMIC(class_name) 相当于在类中添加如下声明相当于在类中添加如下声明 : :

protected: protected:

static CRuntimeClass* PASCAL _GetBaseClass(); static CRuntimeClass* PASCAL _GetBaseClass();

public: public:

//// 静态成员静态成员 CRuntimeClassCRuntimeClass ,给此派生类添加了运行时类信息,给此派生类添加了运行时类信息 ,,

//// 这样就可以使用这样就可以使用 CRuntimeClassCRuntimeClass 成员判断类信息了。成员判断类信息了。

//// 此成员名字格式为此成员名字格式为 "class"+""class"+" 类名类名 ",RUNTIME_CLASS()",RUNTIME_CLASS() 宏就是返回此结构宏就是返回此结构

的指针的指针

static const AFX_DATA CRuntimeClass class##class_name; static const AFX_DATA CRuntimeClass class##class_name;

virtual CRuntimeClass* GetRuntimeClassvirtual CRuntimeClass* GetRuntimeClass() const;() const;

Page 29: 第 3 章  MFC 应用程序框架

进一步理解进一步理解 RUNTIME_CLASSRUNTIME_CLASS

IMPLEMENT_DYNAMIC:IMPLEMENT_DYNAMIC:

#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \

IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)

  

#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, #define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema,

pfnNew) \pfnNew) \

//// 返回基类运行时信息结构的指针返回基类运行时信息结构的指针

CRuntimeClass* PASCAL class_name::_GetBaseClass() \CRuntimeClass* PASCAL class_name::_GetBaseClass() \

{ return RUNTIME_CLASS(base_class_name); } \{ return RUNTIME_CLASS(base_class_name); } \

//// 初始化本类的运行时信息初始化本类的运行时信息 ,, 依次为类名、大小,版本依次为类名、大小,版本 ,NULL,,NULL, 基类基类

AFX_COMDAT const AFX_DATADEF CRuntimeClassAFX_COMDAT const AFX_DATADEF CRuntimeClass

class_name::class##class_name = { \class_name::class##class_name = { \

#class_name, sizeof(class class_name), wSchema, pfnNew, \#class_name, sizeof(class class_name), wSchema, pfnNew, \

&class_name::_GetBaseClass, NULL }; \&class_name::_GetBaseClass, NULL }; \

//// 返回运行时类信息返回运行时类信息 ,, 重载了重载了 CObjectCObject 的的 GetRuntimeClass,GetRuntimeClass,

//// 使得使得 CObjectCObject 中声明的接口对具体的派生类有效中声明的接口对具体的派生类有效

CRuntimeClass* class_name::GetRuntimeClass() const \CRuntimeClass* class_name::GetRuntimeClass() const \

{ return RUNTIME_CLASS(class_name); } \{ return RUNTIME_CLASS(class_name); } \

Page 30: 第 3 章  MFC 应用程序框架

进一步理解进一步理解 RUNTIME_CLASSRUNTIME_CLASS

DYNCREATEDYNCREATE 支持支持类的实例动态生成支持类的实例动态生成支持方法方法 : :

添加声明添加声明 :DECLARE_DYNCREATE( class_name ) :DECLARE_DYNCREATE( class_name )

添加实现添加实现 :IMPLEMENT_DYNCREATE( class_name, base_class_name ):IMPLEMENT_DYNCREATE( class_name, base_class_name )

#define DECLARE_DYNCREATE(class_name) \#define DECLARE_DYNCREATE(class_name) \

//// 具有具有 DYNAMICDYNAMIC 支持支持

DECLARE_DYNAMIC(class_name) \DECLARE_DYNAMIC(class_name) \

//// 对象建立支持对象建立支持

static CObject* PASCAL CreateObject();static CObject* PASCAL CreateObject();

类的声明类的声明类的声明类的声明

类的实现类的实现类的实现类的实现

Page 31: 第 3 章  MFC 应用程序框架

IMPLEMENT_DYNCREATE(class_name, base_class_name):IMPLEMENT_DYNCREATE(class_name, base_class_name):

#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \

//// 动态建立对象动态建立对象

CObject* PASCAL class_name::CreateObject() \CObject* PASCAL class_name::CreateObject() \

{ return new class_name; } \{ return new class_name; } \

//// 填写运行时类信息,与填写运行时类信息,与 DYNAMICDYNAMIC 不同的是,有不同的是,有 pfnNewpfnNew 参数参数

IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF,

class_name::CreateObject)class_name::CreateObject)

进一步理解进一步理解 RUNTIME_CLASSRUNTIME_CLASS

Page 32: 第 3 章  MFC 应用程序框架

3.10 对象的动态创建

3) 3) 对象类信息表的提取对象类信息表的提取