《深入浅出MFC》– Document-View深入探讨
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深入探讨的更多相关文章
- 深入浅出MFC——Document-View深入探讨(五)
1. MFC之所以为Application Framework,最重要的一个特征就是它能够将管理数据的程序代码和负责数据显示的程序代码分离开来,这种能力由MFC的Document/View提供.Doc ...
- 《深入浅出MFC》下载
百度云及其他网盘下载地址:点我 编辑推荐 <深入浅出MFC>内含光盘一片,书中所有原始码与可执行文件尽在其中. 作者简介 侯俊杰,先生不知何许人也,闲静少言,不慕荣利.好读书,求甚解:每有 ...
- 深入浅出MFC——MFC六大关键技术仿真(二)
1. 仿真MFC目的:以MFC为例,学习application framework的内部运行.MFC六大关键技术: (1)MFC程序的初始化过程 (2)RTTI(Runtime Type Inform ...
- 深入浅出MFC——MFC骨干程序(四)
1. 熟记MFC类层次结构: 2. AppWizard可以为我们制作出MFC程序骨干: 3. Document/View支撑你的应用程序:Document/View的价值在于,这些MFC类已经把一个应 ...
- 【笔记】《深入浅出MFC》第5章 总观Application Framework
凝聚性强.组织化强的类库就是Application Framework.一组合作无间的对象,彼此藉消息的流动而沟通,并且互相调用对方的函数以求完成任务,这就是Application Framework ...
- 评侯捷的<深入浅出MFC>和李久进的<MFC深入浅出>
侯捷的<深入浅出mfc>相信大家都已经很熟悉了,论坛上也有很多介绍,这里我就不多说了. 而李久进的<mfc深入浅出>,听说的人可能就少得多.原因听说是这本书当时没有怎么宣传,而 ...
- 深入浅出MFC学习笔记 消息
本章将会对MFC的消息映射和 命令传递机制做深入探讨. MFC规定了消息传递的路线,消息会按照这个路线传递下去,找不到归宿的话就交给DefWindowProc. 在产生窗口之前,如果我们在创建窗口时指 ...
- 深入浅出MFC——Win32程序基本概念(一)
1. Windows程序分为“程序代码”和“UI资源”,下图所示: 2. Windows支持动态链接(应用程序所调用的Windows API函数是在“执行时期”才链接上的).Windows程序调用的函 ...
- 《深入浅出MFC》系列之运行时类型识别(RTTI)
/********************************************************************************** 发布日期:2017-11-13 ...
随机推荐
- Siebel 基础入门--权限控制
企业应用最基本的要求就是只授予用户在他工作职责范围内的权限,一般而言,这种权限都包含两种,一种是对于相应的功能的可见性(或者形象地说,菜单的可见 性,这个是应用层面界面的,这种权限在Siebel里称为 ...
- ubuntu安装google test
google test 简称gtest,是一个C/C++的单元测试框架,它的代码在github仓库,使用起来还是挺方便的. 安装 先确保PC上有安装cmake: sudo cmake --versio ...
- 配置环境变量时,cmd下运行java -version,报错:找不到或无法加载主类 -version
这个方面适用于报错为:java 找不到或无法加载主类,一般是找不到类的路径,问题出在CLASSPATH环境变量上,当然这是大多数.大概率的出错点 不排除根据个人情况不况,所以想起来伟大领袖毛主席的话: ...
- 传统数据仓库项目的优化手段 (针对 Oracle+DataStage )
普通手段 分区,HASH-JOIN,数据仓库函数,物化视图,位图索引等等为大伙在数据仓库常用的技术, 而下面列举的tips为项目中常用的优化手段/技巧,绿色背景highlight的部分属于非常规手段, ...
- 『看球笔记』20131230切尔西vs利物浦,赛后复盘聊聊球
2013-12-30 第十九轮英超联赛 切尔西vs利物浦 看着这张板凳合照… 有木有一种心里哇凉哇凉的感觉. 赛后whoscored的平均位置图 左边车子,右边我军 阿格回 ...
- MySQL优化 ----开篇
今天,数据库的操作越来越成为整个应用的性能瓶颈,Mysql优化则是一个经常要谈的问题了. 谈起MySQL优化,咱们先简单谈一下Mysql: Mysql是最流行的关系型数据库管理系统,在WEB应用方面M ...
- SpringMVC学习记录三——8 springmvc和mybatis整合
8 springmvc和mybatis整合 8.1 需求 使用springmvc和mybatis完成商品列表查询. 8.2 整合思路 springmvc+mybaits的 ...
- File,FileInfo,Directory,DirectoryInfo
两者的共同点: 一:都用于典型的操作,如复制.移动.重命名.创建.打开.删除和追加到文件 二:默认情况下,将向所有用户授予对新文件的完全读/写访问权限. 两者的区别: File类是静态类, ...
- C# Response 下载
//TransmitFile实现下载 protected void Button1_Click(object sender, EventArgs e) { /* 微软为Response对象提供了一个新 ...
- 【luogu P3879 [TJOI2010]阅读理解】 题解
题目链接:https://www.luogu.org/problemnew/show/P3879 我先说一句: 我永远都喜欢StellaSTL 这个题,很明显就是 trie树 hash map+vec ...