现在的位置: 首页 > 综合 > 正文

看深入浅出MFC

2018年05月04日 ⁄ 综合 ⁄ 共 8150字 ⁄ 字号 评论关闭

作者谈到了四大难点:C++语言,MFC庞大的类库,windows程序基本动作传统不见了,对象导向的观念与application framework的包装。

其中的关键技术:RTTIdynamic creationpersistenceserialization),message mappingcommand routiong等核心技术。(主要的是宏实现)

 

Windows程序的事件驱动特性:消息的产生,获得,分派,判断,处理。

第一:定义了一个数据结构struct MSGMAP_ENTRY

{

         UINT nMessage;

         Long (*pfn)(HWND,UINT,WPARAM,LPARAM);

};

然后在定义了两个数组:_messageEntries[]_commandEntries[],把程序中欲处理的消息和消息处理例程的关联性建立起来:

Struct MSGMAP_ENTRY _messageEntries[]

{

         WM_CREATE,OnCreate,

         WM_PAINT,OnPaint,

}

Struct MSGMAP_ENTRY _commandEntries[]

{

         IDM_ABOUT, OnAbout,

         IDM_FILEIOPEN,OnFileOpen,

}

 

对话框的运作:模态对话框和非模态对话框。为了作出一个对话框,程序员必须准备两样东西:一个就是对话框模板,决定了对话框的大小,字形,内部有哪些控件,在什么位置,另外一个就是对话框函数,它通常只处理WM_INITDIALOGWM_COMMAND两个消息。

 

WINDOWS程序的生与死:

RegisterClass,CreateWindows,ShowWindow,UpdateWindow,while(GetMessage(&msg。。)){TranslateMessage,DispatchMessage}

 

虚拟函数和多态:首先要是多态的话,那么就是要用指针或者引用,另外一个就是要定义了虚拟的函数,即用关键字virtual定义的函数。多态的目的,就是要让处理基类的对象的程序代码,能够完全透通的继续适当处理派生类的对象。

MFC中的两个十分重要的虚拟函数:与document有关的Serialize函数和与view有关的OnDraw函数。分别再自己的CMyDocCMyView中改写这两个虚拟函数。

类型和对象大剖析:这里主要谈到的就是虚拟表的作用,vptr

 

向下转型时要注意可能截断一部分派生类的内容。

静态成员(变量和函数):static指定了这个变量或者是函数是类的一部分,而不是对象的一部分,一般不在构造函数中初始化这个变量。如果将static变量定义成一个private的,那么就要定义一个static的成员函数。Static成员函数没有this指针的这种性质,正是我们的MFC应用程序在准备callback函数时所需要的。

四种不同的对象生存方式(in stack,in heap,global,local static

执行期型别信息(RTTI):编译时需选用/GR选项(它的意思是enable C++ RTTI),包含typeinfo.h,新的typeid运算子。这是一个多载运算子。

动态生成(Dynamic Create):serialize序列化,就是做有关文件读写的永续存留动作。因为载ram中的东西,只要断电就会消失,所以唯一能够persistence的方法是把它写到文件去。

异常处理(Exception Handling):

 

MFC六大关键技术之仿真:

MFC程序的初始化过程:也就是几个类之间的关系:CObject CcmdTargetCWinThread,CWinAppCWndCViewCFrameWndCDocument之间的关系

 

RTTI执行期型别信息:除了要用到/GR选项,包含typeinfo.h和使用新的typeid运算子之外,还要具备IsKindOf的能力,测试在执行期某个对象是否属于某种类别,并返回TRUE或者FALSE

类别型录网与CRuntimeClass:这里其实是定义了一个结构体,在这个结构体中有一个staticfirst指针,然后是一个串行的单链表,这个链表的next指向的是它的父类。

DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏:而根CObject不能套用现成的宏DECLARE_DYNAMIC宏。

IsKindOf(类别辨识):只需要找这个链表中的base指针就行了。

 

Dynamic Creation动态生成:如果能够把类别的大小记录在类别型录中,把CRuntimeClass::CreateObject也记录在类别型录中,当程序在执行时期获得一个类别名称,它就可以在类别型录网中找出对应的元素,然后调用其CRuntimeClass::CreateObject,产生出对象。

         DELARE_DYNCREATEIMPLEMENT_DYNCREATE宏:而CreateObject非常的简单,只要new就好了,但是这里的问题是什么时候释放对象呢?

 

 

Persistence永续留存:将数据写到文件中去。在文档/视图结构中,文件都放在document中,我们只要把其中的成员变量依次写进文件即可。成员变量可能是个对象,而面对对象,我们首先应该记载其类别名称,然后才是对象中的资料。

         Serialize(文档读写):要将<<>>两个运算子多载话,还要将Serialize函数放入类别声明之中,所以还是使用宏DECLARE_SERIALIMPLEMENT_SERIAL

Message Mapping 消息映射:宏DECLARE_MESSAGE_MAP相当于static AFX_MSGMAP_ENTRY _messageEntries[];static AFX_MSGMAP messageMap;virtual AFX_MSGMAP *GetMessageMap() const;再用BEGIN_MESSAGE_MAP实现之。

 

Message Routing 消息绕行:MFC对于消息绕行的规定是:

如果是一般的windows消息(WM_,一定是由衍生类流向基础类别,没有旁流的可能。

如果是命令消息WM_COMMAND,那就有奇特的路线了:

命令消息接收物的类型                    处理次序

Frame窗口                              1.View2.Frame窗口本身 3.CWinApp对象

View                                    1.View本身 2.Document

Document                                  1.Document本身 2.Document Template

 

第四章:Visual C++整合开发环境

 

第五章:总观Application Framework:这里主要的是谈到了MFC的类别,作者把它分成一般的类,API类,应用框架类,高级抽象类,操作系统扩展。凡衍生自CWnd类别的才能收到WM_消息,WM_COMMAND除外。CcmdTarget类别才能处理命令消息WM_COMMAND

以下是几个常见的Afx全局函数:

AfxWinInitAfxBeginThreadAfxEndThreadAfxFormatString1AfxFormatString2AfxMessageBoxAfxOutputDebugStringAfxGetAppAfxGetMainWndAfxGetInstanceAfxRegisterClass

MFC宏:(这些宏的定义可以在AFX.H中看到的)

宏名称                             提供功能

DECLARE_MESSAGE_MAP         声明消息映射表数据结构

BEGIN_MESSAGE_MAP            开始消息映射表的建制

ON_COMMAND                   增加消息映射表中的项目

ON_CONTROL                    增加消息映射表中的项目

ON_MESSAGE                    增加消息映射表中的项目

ON_OLECMD                      增加消息映射表中的项目

ON_REGISTERED_MESSAGE        增加消息映射表中的项目

ON_REGISTERED_THREAD_MESSAGE        增加消息映射表中的项目

ON_THREAD_MESSAGE             增加消息映射表中的项目

ON_UPDATE_COMMAND_UI         增加消息映射表中的项目

END_MESSAGE_MAP               结束消息映射表的建置

 

DECLARE_DYNAMIC              执行期类型信息

IMPLEMENT_DYNAMIC            执行期类型信息

DECLARE_DYNCREATE            动态生成

IMPLEMENT_DYNCREATE          动态生成

DECLARE_SERIAL                 对象内容的文件读写

IMPLEMENT_SERIAL               对象内容的文件读写

DECLARE_OLECREATEOLE         对象的动态生成

IMPLEMENT_OLECREATEOLE       对象的动态生成

 

第六章:MFC程序的生死因果:

WinMainRegisterClassCreateWindowMessage Loop,窗口函数(Window Procedure)等等动作。

 

第七章:简单而完整:MFC骨干程序

这里的问题主要是说文档/视图结构,对于文档来说,在MFC设计的时候,并不知道,究竟要存入什么函数,但是可以有一个虚拟函数,在派生类CMYDocument中改写Serialize函数。

OnPaint主要是做只输出到屏幕而不到打印机的动作。

 

第八章:文档/视图结构深入探讨

把数据管理和显示方法分离开来,需要考虑下列几个议题:

程序的哪一部分拥有资料,程序的哪一部分更新资料,如何以多种方式显示资料,如何让资料的更改有一致性,如何存储资料,如何管理使用者接口。不同的数据类型可能需要不同的使用者接口,而一个程序可能管理多种类型的资料。

DocumentMFC中被Cdocument具体化。但是它什么也没有做,因此要在派生类中重写虚函数Serialize

CDocTemplate管理Cdocument/Cview/CframeWnd

然后在VC中定义了很多的数据结构,

类别        C++模板          Serializable         Dumpable             typesafe

CArray         yes                yes               yes                   no

CTypedPtrArray   yes               depends             yes                   yes

CByteArray       no                 yes             yes                    yes

CDWordArray     no               yes                  yes                 yes

CObArray         no              yes              yes                       no

CPtrArray          no             no                yes                    no

CStringArray      no             yes                  yes                yes

CWordArray       no            yes                  y                  y

CUintArray          n           n                    y                  y

CList              y             y                   y                    n

CTypedPtrList        y              depends           y                   y

CObList            n              y                    y                   n

CPtrList            n             n                     y                     n

CString List         n                   y                    y            y

CMap              y                   y                 y              n

CTypedPtrMap         y               depends               y                 y

CMapPtrToWord       n               n                  y                    n

CMapPtrToPtr         n              n                   y             n

CMapString ToOb      n             y                   y               n

CMapStingToString     n          y                     y                  y

CMapWordToOb         n         y                     y                  n

CMapWordToPtr           n             n                    y                n

 

 

Serializable的必要条件:

1.CObject继承下来,如此一来可保有RTTIDynamic Creation等机能。

 2.类别的声明部分必须要有DECLARE_SERIAL宏,此宏需要一个参数:类别名称

3.类别的实作部分必须要有IMPLEMENT_SERIAL宏。此宏需要三个参数:一个实类别名称,二是父类别名称,三是schema no

4.改写Serialize虚拟函数,使它能够适当地把类别的成员变量写入文件中.

5.为此类别加上一个缺省构造函数。这个条件是必要的,因为若一个对象来自文件,MFC必须先动态生成它,而且在没有任何参数的情况下调用其构造函数,然后才从文件中读出对象文档。

CObject类别:

CView之中的三个虚函数:

CView::OnInitialUpdate:负责View的初始化

CView::OnUpdate:当Framework调用此函数,表示Document的内容已有改变

CView::OnDrawFramework在收到WM_PAINT之后调用OnPaint,然后调用此函数。此函数应负责更新View窗口的内容。

让所有的View窗口同步更新的关键在于两个函数

CDocument::UpdateAllViews:如果这个函数执行起来,它会巡访所有隶属同一个Document的各个View,找到一个就通知一个,而所谓的通知就是调用ViewOnUpdate函数。

 

第九章:消息映射与命令绕行

所有UI对象状态的维护可以依赖所谓的UPDATE_COMMAND_UI消息,比如命令项状态(打勾或没有打勾,灰色或者正常)。

 

第十章:MFC与对话框

 

可卷动的窗口:CScrollView

需要做如下的事情:定义Document大小。如果没有大小,Framework就没有办法计算滚动条尺寸以及滚动比例。这个大小可以是常数,也可以是个存储在每一个Document中的变量,随着执行期变动。以CScrollView取代CView。只要Document的大小改变,就将尺寸传给CScrollViewSetScrollSizes函数。如果程序设定Document为固定大小,那么当然只要一开始做一次滚动条设定动作即可。注意逻辑坐标和窗口坐标之间的转换。修正鼠标坐标,在作画的时候,必须由以视窗绘图区左上角为原点的窗口坐标系统,改变为以文件左上角为原点的逻辑坐标系统。(DPtoLP

 

多重窗口和多重显示:

MDI和分裂窗口:动态分裂窗口由CSplitterWnd提供服务。在AppWizard的第四步时由Windows styles。选择use split window。动态窗口的每一个窗口都使用相同的View类别,因此显示出来的东西千篇一律,第二,窗口之间并非完全独立。但是可以动态的增减窗口。

静态分裂窗口分裂窗口的个数一开始就固定了。每一个窗口的活动完全独立自主。动态分裂窗口的诞生是靠CSplitterWnd::Create,静态分裂窗口的诞生则是靠CSplitterWnd::CreateStatic函数。然后CreateView

 

COM控件:为什么组件在此为为COMActiveX control两种?有什么不同。简单得说,COM是一些写好的C++类别。基本上C++类别本来就是具有重复使用性,COM只是把他们多做一些必要的包装,连同其他阻援放在一起成为一个包裹。当你需要某个COMCOM Gallery给你的是该COM的源代码。ActiveX controls不一样。当你选用某个ActiveX controlCOM Gallery当然也会为你填入一些吗,但他们不是组件的本体。哪些吗只是使用组件时所必须的码,组件本身在.OCX文件中,通常注册后的OCX文件都放在winows/System目录。ocx就是ActiveX Control

ActiveX Control 基础观念: 属性    方法    事件

OCX的方法像C++类中的成员函数,但它们被限制在一个有限的集合之中,集合内的名单包括AddItemRemoveItemMoveRefresh等等。

一般而言属性包括Ambient 属性,Extended属性,Stock属性(BackColorFontNmaeCaption),Custom属性。

 

ActiveX Controls的五大步骤:

1.        建立项目时,在第三步选择ActiveX controls

2.        进入Component Gallery,把ActiveX Controls安插到程序中

3.        使用ActiveX Controls。通常我们在对话框中使用它。我们可以把资源编辑器的工具箱里头的ActiveX Controls拖放到目标对话框中

4.        利用ClassWizard产生对话框类别,并处理相关的Message Maps,消息处理,变量定义,对话框函数

5.        编译链接

 

 

 

 

抱歉!评论已关闭.