1.其实Document/View不是什么新东西,Xerox PARC实验室是这种观念的滥觞。它是Smalltalk环境中的关键性部分,在那里它被称为Model-View-Controller(MVC)。其中的Model就是MFC的Document,而Controller相当于MFC的Document Template。

2.Document在MFC的CDocument里头被实例化。CDocument本身并无实际用途,他只是提供一个空壳。你应该从它派生一个自己的类,然后改写负责文件读写操作的Serilize函数。由于CDocument派生自CObject,所以他就有了CObject所支持的一切性质,包括RTTI、动态创建、文件读写。又由于它也派生自CCmdTarget,所以它可以接受来自菜单或工具栏的WM_COMMAND消息。

3.View负责呈现Document中的数据。

View在MFC的CView里头被实例化,同样应该派生属于自己的View类,并且在类中改写专门负责显示数据的OnDraw函数或OnPrint函数。由于CView派生自CWnd,所以它可以接收一般的Windows消息,又由于它也派生自CCmdTarget,所以它可以接受来自菜单或工具栏的WM_COMMAND消息。

在MFC中,一旦WM_PAINT发生,Framework会自动调用OnDraw函数,View事实上是个没有边框的窗口。真正出现时,其外围还有一个有边框的窗口,我们称之为Frame窗口。

4.Document Frame(View Frame)

你可能愿意在使用者操作TEXT数据时,换一套TEXT专用的使用者界面,在使用者操作BITMAP数据时,换一套BITMAP专用的使用者界面。这份工作正式Frame窗口负责。

5.Document Template

每当使用者欲打开一份文件,程序应该做出Document、View、Frame各一份。这三个成为一个运行单元,由所谓的Document Template掌管。MFC有一个CDocTemplate负责此事,他又有两个派生类,分别是CMultiDocTemplate和CSingleDocTemplate。如果你的程序能够处理两中数据类型,你必须制造两个Document Template,并使用AddDocTemplate函数将他们一一加入系统之中。

6.谁来管理Document Template呢?是CWinApp。来看看InitInstance中应有的相关行为:

CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
    IDR_MFCTYPE,
    RUNTIME_CLASS(CMfcDoc),
    RUNTIME_CLASS(CChildFrame), // custom MDI child frame
    RUNTIME_CLASS(CMfcView));
AddDocTemplate(pDocTemplate);

Document Template产生Document/View/Frame的行动:

7.当使用者单机File/New命令项,这一命令由CWinApp::OnFileNew接手处理。然后调用CDocManager::OnFileNew->CMultiDocTemplate::OpenDocumentFile.

在OpenDocumentFile中CreateNewDocument动态产生Document,CreateNewFrame动态产生Document Frame。在CreateNewFrame中,不仅Frame被动态创建出来了,其对应窗口也以LoadFrame产生出来了。Document Frame窗口产生之际由于WM_CREATE的产生引发CFrameWnd::OnCreate被唤起。

不仅View对象被动态创建出来了,其对应的实际Windows窗口也以Create函数产生出来。

8.CDocTemplate、CDocument、CView、CFrameWnd 之间的关系

①CWinApp 拥有一个对象指针:CDocManager* m_pDocManager。

②CDocManager 拥有一个指标串行 CPtrList m_templateList, 用来维护一系列的 Document Template。一个程序若支持两「种」文件型态,就应该有两份Document Templates,应用程序应该CMyWinApp::InitInstance 中以 AddDocTemplate 将这些 Document Templates 加入由 CDocManager 所维护的链表之中。

③CDocTemplate 拥有三个成员变数, 分别持有 Document 、View、Frame 的 CRumtimeClass 指针,另有一个成员变量 m_nIDResource,用来表示此 Document 显现时应该采用的 UI 对象。这四份数据应该在 CMyWinApp::InitInstance 函数 建构 CDocTemplate(注1)时指定之,成为建构式的参数。当使用者欲打开一 份文件(通常是借着【File/Open】或【File/New】命令项),CDocTemplate 即可借由 Document/View/Frame 之CRuntimeClass 指标(注2)进行动态生成。

注1:在此我们必须有所选择,要不就使用 CSingleDocTemplate,要不就使用 CMultiDocTemplate , 两者都是 CDocTemplate 的衍生类别。如果你选用 CSingleDocTemplate,它有一个成员变数 CDocument* m_pOnlyDoc,亦即它一次只能打开一份 Document。如果你选用 CMultiDocTemplate,它有一个成员变数 CPtrList m_docList,表示它能同时打开多个 Documents。

④CDocument 有一个成员变数 CDocTemplate* m_pDocTemplate,回指其Document Template;另有一个成员变量 CPtrList m_viewList,表示它可以同时维护一系列的 Views。

⑤CFrameWnd 有一个成员变量 CView* m_pViewActive, 指向目前正作用中的View。

⑥CView 有一个成员变量 CDocument* m_pDocument,指向相关的 Document。

9.MFC Collection Classes

MFC Collection classes所支持的对象中,有两种特别需要说明,一是Ob,一是Ptr:

①Ob表示派生自CObject的任何对象。MFC提供CObList、CObArray两种类。

②Ptr表示对象指针。MFC提供CPtrList、CPtrArray两种类。

10.Serializable的必要条件

欲让一个对象有Serialize能力,它必须派生自一个Serializable类。一个类意欲成为Serializable,必须有下列五大条件;

1.  从CObject派生下来。如此一来可保有RTTI、DynamicCreation等机能。

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

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

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

5.  为经类加上一个default构造函数(也就是无参数之构造函数)。这个条件常为人所忽略,但它是必要的,因为若一个对象来自文件,MFC必须先动态创建它,而且在没有任何参数的情况下调用其构造函数,然后才从文件中读出对象数据。

一个类若要能够进行Serializable操作,必须准备Serialize函数,并且在“类别型录网”中自己的那个CRuntimeClass元素里的schema字段里设置0xFFFF以外的号码。

11.CArchive类管理文件缓冲区。它是Serialize的对象。CArchive针对许多C++数据类型,windows数据类型以及CObject派生类定义了operator<<和operator>>重载运算符。

一个C++类如果想要有Serialization机制,就得直接或间接派生自CObject。为的是从CObject派生下列三个运算符:

_AFX_INLINE CArchive &AFXAPI operator<<(CArchive&ar,const CObject*pOb);

_AFX_INLINE CArchive &AFXAPI operator>>(CArchive&ar,CObject*&2pOb);

_AFX_INLINE CArchive &AFXAPI operator>>(CArchive&ar,const CObject*&pOb);

一个类如果希望有Serialization机制,它的第二要件就是使用SERIAL宏。

这个宏包含DYNCRETE宏,并且在类的声明之中加上:

friend CArchive &AFXAPI operator>>(CArchive&ar,class_name* &pOb);

在类的应用程序文件中加上:

CArchive &AFXAPI operator>>(CArchive&ar,class_name*&pOb) \

{ pOb=(class_name*)ar.ReadObject(RUNTIME_CLASS(class_name)); \

return ar;}

12.当多个视图显示同一个文档,为了保持各个视图操作的文档内容的一致性,需要以消息通知使用同一份文档的其他视图,CView中有三个虚函数:

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

2:CView::OnUpdate,当FrameWork调用此函数时,表示Document的内容已经发生了变化。

3:CView::OnDraw:在WM_PAINT消息时会调用此函数,此函数负责更新View窗口的内容。

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

1:CDocument::UpdateAllViews,它会遍历使用这个文档的各个视图,逐个调用它们的OnUpdate函数。

2:CView::OnUpdate,这是个虚函数,可以改写。它的作用就是告诉View,document的内容已经改变,你需要更新了。

具体步骤为:
    1:在CView中调用GetDocument获得CDocument指针。

2:在CView中调用CDocument::OnUpdateAllViews;

3:所有使用这一份Document的view都被调用OnUpdate。

原文博客:http://www.blogfshare.com

《深入浅出MFC》– Document-View深入探讨的更多相关文章

  1. 深入浅出MFC——Document-View深入探讨(五)

    1. MFC之所以为Application Framework,最重要的一个特征就是它能够将管理数据的程序代码和负责数据显示的程序代码分离开来,这种能力由MFC的Document/View提供.Doc ...

  2. 《深入浅出MFC》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <深入浅出MFC>内含光盘一片,书中所有原始码与可执行文件尽在其中. 作者简介 侯俊杰,先生不知何许人也,闲静少言,不慕荣利.好读书,求甚解:每有 ...

  3. 深入浅出MFC——MFC六大关键技术仿真(二)

    1. 仿真MFC目的:以MFC为例,学习application framework的内部运行.MFC六大关键技术: (1)MFC程序的初始化过程 (2)RTTI(Runtime Type Inform ...

  4. 深入浅出MFC——MFC骨干程序(四)

    1. 熟记MFC类层次结构: 2. AppWizard可以为我们制作出MFC程序骨干: 3. Document/View支撑你的应用程序:Document/View的价值在于,这些MFC类已经把一个应 ...

  5. 【笔记】《深入浅出MFC》第5章 总观Application Framework

    凝聚性强.组织化强的类库就是Application Framework.一组合作无间的对象,彼此藉消息的流动而沟通,并且互相调用对方的函数以求完成任务,这就是Application Framework ...

  6. 评侯捷的<深入浅出MFC>和李久进的<MFC深入浅出>

    侯捷的<深入浅出mfc>相信大家都已经很熟悉了,论坛上也有很多介绍,这里我就不多说了. 而李久进的<mfc深入浅出>,听说的人可能就少得多.原因听说是这本书当时没有怎么宣传,而 ...

  7. 深入浅出MFC学习笔记 消息

    本章将会对MFC的消息映射和 命令传递机制做深入探讨. MFC规定了消息传递的路线,消息会按照这个路线传递下去,找不到归宿的话就交给DefWindowProc. 在产生窗口之前,如果我们在创建窗口时指 ...

  8. 深入浅出MFC——Win32程序基本概念(一)

    1. Windows程序分为“程序代码”和“UI资源”,下图所示: 2. Windows支持动态链接(应用程序所调用的Windows API函数是在“执行时期”才链接上的).Windows程序调用的函 ...

  9. 《深入浅出MFC》系列之运行时类型识别(RTTI)

    /********************************************************************************** 发布日期:2017-11-13  ...

随机推荐

  1. Python类三种方法,函数传参,类与实例变量(一)

    1 Python的函数传递: 首先所有的变量都可以理解为内存中一个对象的'引用' a = 1 def func(a): a = 2 func(a) print(a) # 1 a = 1 def fun ...

  2. ORACLE_PROCEDURE_DROPTABLE

    WEBSITE:https://stackoverflow.com/questions/14564641/drop-a-table-in-a-procedure Qusetion:Hou to use ...

  3. I want to be a Great Web Front-end Developer

    有时觉得特别的浮躁,可能是每天春运般的挤地铁,随处可见因为一点小磕小蹭吹胡子瞪眼睛的人,可能是身边的人貌似一下子都好有钱,买房买车或者买第N套房. 很想静下来心寻找到自己inner pace,但是忽然 ...

  4. python编写的简单的mysql巡检脚本

    准备工作:1    安装python 3.5,本次使用源码安装.2    安装psutil模块,使用python3.5自带的easy_install包直接运行cd /opt/python3/bin./ ...

  5. May 12th 2017 Week 19th Friday

    Love asks faith, and faith asks firmness. 爱情要求忠诚,而忠诚要求坚贞. Love, as well as many other relations amon ...

  6. Perl Unicode全攻略

    Perl Unicode全攻略 耐心看完本文,相信你今后在unicode处理上不会再有什么问题. 本文内容适用于perl 5.8及其以上版本. perl internal form 在Perl看来, ...

  7. Django:Django的路由系统

    一,URLconf配置 1,基本格式 from django.conf.urls import url urlpatterns = [ url(正则表达式, views视图函数,参数,别名), ] 2 ...

  8. 记忆化搜索,FatMouse and Cheese

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1107 http://acm.hdu.edu.cn/showpro ...

  9. 【洛谷P3853】 [TJOI2007]路标设置

    路标设置 题目链接 此题和跳石头很相似,都是二分答案,模拟判断是否可行 #include<iostream> #include<cstdio> using namespace ...

  10. 实现虚拟(Virtual)DOM

    Virtual DOM算法 把一个div元素的属性打印出来,如下: 可以看到仅仅是第一层,真正DOM的元素是非常庞大的,这也是DOM加载慢的原因. 相对于DOM对象,原生的JavaScript对象处理 ...