<深入浅出mfc>第8章Document-View 深入探讨

来源:互联网 发布:centos7网络配置 rules 编辑:程序博客网 时间:2024/04/29 09:49

第8章Document-View 深入探讨

代码的位置在点击这下载:http://download.csdn.net/detail/caidaoqq/6951265

1.   CDocTemplate管理CDocument / CView / CframeWnd


图8-2 解释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)进行动态生成。

■ CDocument 有一个成员变量CDocTemplate* m_pDocTemplate,回指其Document

Template;另有一个成员变量CPtrList m_viewList,表示它可以同时维护一系列

的Views。

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

View 。

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

 

2.   Scribble Step1 的Document---数据结构设计

MFC Collection Classes。它们分为三种类型,用来管理一大群对象:

■ Array:数组,有次序性(需依序处理),可动态增减大小,索引值为整数。

■ List:双向串行,有次序性(需依序处理),无索引。串行有头尾,可从头尾

或从串行的任何位置安插元素,速度极快。

■ Map:又称为Dictionary,其内对象成对存在,一为键值对象(key object),

一为实值对象(value object)。

 

CPenPaintTestDoc的成员变量:

■  m_strokeList:这是一个CObList 对象,代表一个串行。串行中的元素是什么型

态?答案是CObject*。但实际运作时,我们可以把基础类别之指针指向衍生类

别之对象。现在我们想让这个串行成为「由CStroke对象构成的串行」,因此显然CStroke

必须衍生自

CObject 才行,而事实上它的确是。

■  m_nPenWidth:每一线条都有自己的笔宽,而目前使用的笔宽记录于此。

■  m_penCur:这是一个CPen 对象。程序依据上述的笔宽,配置一支笔,准备用

来画线条。笔宽可以指定。注意,笔宽的设定对象是线条,不是单一的点,也不是一整张图。

 

CPenPaintTestDoc的成员函数:

■ OnNewDocument、OnOpenDocument、InitDocument。产生Document 的时机有二,

一是使用者选按【File/New】,一是使用者选按【File/Open】。当这两种情况

发生,Application Framework会分别调用Document 类别的OnNewDocument

OnOpenDocument。

■  NewStroke。这个函数将产生一个新的CStroke对象,并把它加到串行之中

结果:产生了一个新线条,设定了线条宽度,并将新线条加入串行尾端

■  DeleteContent。利用CObList::RemoveHead把串行的最前端元素拿掉。

■  Serialize。这个函数负责文件读写。由于文件掌管线条串行,线条串行又掌管

各线条

 

CStroke的成员变量

■  m_pointArray:这是一个CArray 对象,用以记录一系列的CPoint 对象,这些

CPoint 对象由鼠标坐标转化而来。

■  m_nPenWidth:一个整数,代表线条宽度。虽然ScribbleStep1 的线条宽度是

固定的。

 

CStroke的成员函数

■  DrawStroke :绘图原本是View 的责任,为什么却在CStroke 中有一个

DrawStroke?因为线条的内容只有CStroke 自己知道,当然由CStroke 的成

员函数把它画出来最是理想。这么一来,View 就可以一一调用线条自己的绘

图函数,很轻松。

■  Serialize:让我们这么想象写档动作:使用者下命令给程序,程序发命令给文

件,文件发命令给线条,线条发命令给点数组,点数组于是把一个个的坐标点

写入磁盘中。

3.   Scribble Step1 的View:资料重绘与编辑

View 有两个最重要的任务,一是负责资料的显示,另一是负责资料的编辑

 

本例的CPenPaintTestView包括以下特质:

■„解读CPenPaintTestDoc中的资料,包括笔宽以及一系列的CPoint 对象,画在View

窗口上。

■  允许使用者以鼠标左键充当画笔在View 窗口内涂抹,换句话说CPenPaintTestView

必须接受并处理WM_LBUTTONDOWN、WM_MOUSEMOVE、WM_LBUTTONUP

三个消息。

 

View 的重绘动作:GetDocument 和OnDraw

以下是CPenPaintTestView中与重绘动作有关的成员变量和成员函数。

 

CPenPaintTestView的成员变量

     m_pStrokeCur:一个指针,指向目前正在工作的线条。

■  m_ptPrev:线条中的前一个工作点。我们将在这个点与目前鼠标按下的点之间

画一条直线。虽说理想情况下鼠标轨迹的每一个点都应该被记录下来,但如果

鼠标移动太快来不及记录,只好在两点之间拉直线。

 

CPenPaintTestView的成员函数

■   OnDraw:这是一个虚拟函数,负责将Document的数据显示出来。改写它是程

式员最大的责任之一。

■   GetDocument:AppWizard为我们做出这样的码

■   OnPreparePrinting,OnBeginPrinting,OnEndPrinting:这三个CView 虚拟函数将

用来改善打印行为。

 

Serialize:对象的文件读写

对象必须能够永续生存,也就是它们必须能够在程序结束时储存到文件中,并且在程序重新激活时再恢复回来。储存和恢复对象的过程在MFC 之中就称为serialization。负责这件重要任务的,是MFC CObject 类别中一个名为Serialize的虚拟函数,文件的「读」「写」动作均透过它。

Scribble程序的文件读写动作是这么分工的:

■ Framework 调用CPenPaintTestDoc::Serialize,用以对付文件。

CPenPaintTestDoc再往下调用CStroke::Serialize,用以对付线条。

■ CStroke 再往下调用CArray::Serialize,用以对付点数组。

 

Serializable的必要条件:

1. 从CObject 衍生下来。如此一来可保有RTTI、Dynamic Creation 等机能。

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

名称。

3. 类别的实作部份必须有IMPLEMENT_SERIAL 宏。此宏需要三个参数:

一是类别名称,二是父类别名称,三是schemano.。

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

5. 为此类别加上一个default 构造式(也就是无参数之构造式)。这个条件常为

人所忽略,但它是必要的,因为若一个对象来自文件,MFC必须先动态生成

它,而且在没有任何参数的情况下调用其构造式,然后才从文件中读出对象资

料。

0 0
原创粉丝点击