第八章:Document----View深入探讨
MFC之所以为应用程序框架,最重要的特征就是他能够将管理数据的程序代码和负责数据显示的程序代码分离开来。这种能力由文档视图结构提供。Document在MFC的CDocument中被实例化,它本身就是一个空壳,当开发自己的程序时,应该从CDocument派生出一个属于自己的CMyDocument类,并且在类中声明一些成员变量,用以容纳数据。然后再改写Serialize函数,CDocument派生自CObject类,所以它具有CObject所支持的一切性质,包括运行时类型识别,动态创建,文件读写,又由于它派生自CCmdTarget,所以它可以接受来自菜单或工具栏的WM_COMMAND消息。
CView负责数据的显示。CView本身并无用途,它也是提供了一个空壳,当开发程序时,应该从CView派生出一个属于自己的CMyView类,并且在类中改写负责数据显示的OnDraw函数。由于CView派生自CWnd,因此它可以接受一般的Windows消息,又由于它派生自CCmdTarget,所以它可以接收来自菜单或工具栏的WM_COMMAND消息。
View是一个没有边框的窗口,其外围还有一个Frame窗口。
CDocTemplate负责管理Document、View和Frame。它有两个派生类,分别为:CMultiDocTemplate,CSingleDocTemplate。如果程序能够处理两种以上的数据,就必须构造两个DocumentTemplate出来,然后调用CWinApp::AddDocTemplate将它们加入到系统之中。这和程序是不是MDI没有关系。如果程序支持多种数据类型,但是是SDI,那只是每次只能打开一个文件罢了,MDI可以同时打开多个。
CDocTemplate用以管理View,document和Frame。而CWinApp管理CDocTemplate。在CWinApp::InitInstance中构建CDocTemplate:
BoolCMyWinApp::InitInstance()
{
.....
CMultiDocTemplate*pDocTemplate=newCMultiDocTemplate(
IDR_SCRIBYTEP,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CChildFrame),
RUNTIME_CLASS(CMyView);
AddDocTemplate(pDocTemplate);
}
注意构造CView对象和产生View窗口之间的区别。CView类用于管理View窗口,它内部含有要产生的View窗口的句柄,因此必须首先构造CView对象,在调用该类的成员函数如Create函数产生窗口。
由于在构建CDocTemplate时,传递的是document,View和Frame的CRuntimeClass结构,在CDocTemplate内部,会构建调用各自类的构建函数构建这三个对象。这是在CMultiDocTemplate::OpenDocumentFile内实现的。
当使用者单击File/New,CWinApp::OnFileNew函数被调用,然后它又调用CDocManager::OnFileNew,后者又调用CMultiDocTemplate::OpenDocumentFile.此函数调用CreateNewDocument动态创建Document,调用CreateNewFrame动态产生DocumentFrame。然而View的产生就没有这么显而易见了,首先Frame的创建发出WM_CREATE消息,是CFrameWnd::OnCreate被调用,经过一些列调用,在最后调用的CFrameWnd::CreateView内,View对象以及windows窗口都被创建出来。
CWinApp又有一个指向CDocManager的指针,它指向CDoManager类型的对象。在CDocManager类中,有一个指针链表,用来维护一系列的DocumentTemplate,如果一个程序支持两种以上的文件类型,那么就应该调用AddDocTemplate将DocumentTemplate加入到链表中。
CDocTemplate拥有三个成员变量,分别为指向document,view和Frame的CRuntimeClass指针,另一个成员为m_nIDResource。用来表示此Document显现时应该使用的UI对象。这四个成员应该在
CMyWinApp::InitInstance中构造CDocTemplate时指定。然后CDocTemplate可以借助这些参数,动态构建Document,view和Frame。如果是单文档程序,DocumentTemplate就是CSingleDocTemplate,此时它有一个m_pOnlyDoc成员变量,也就是说它只能打开一份文档。如果为多文档应用程序,DocumentTemplate使用的就是CMultiDocTemplate,它有一个成员变量m_docList,此变量为CPtrList类型,指向一系列打开的文档。
CDocument有一个成员变量CDocTemplate,指向它所属的DocumentTemplate。另一个成员变量m_viewList指向它维护的一系列view。
CFrameWnd有一个成员m_pViewActive指向当前活动的View。
CView有一个成员变量,m_pDocument指向相关的Document。
类似于C++中STL中的顺序容器vector和List,MFC也提供了自己的容器类。它们可以分为List,Array,Map;
CArray,CList,CMap为模板类,使用时需要指定元素类型和函数的参数类型。
如CArray<TYPE,ARG_TYPE>a;
CList<TYPE,ARG_TYPE>b;
CMap<KEY,ARG_KEY,VALUE,ARG_VALUE>c;
ARG_TYPE则用来指定函数的参数类型。
类型指针使用时仍然需要指定参数:
CTypedPtrArray<BASE_CLASS,TYPE>a;
CTypedPtrList<BASE_CLASS,TYPE>b;
CTypedMap<BASE_CLASS,KEY,VLAUE>c;
TYPE用以指定元素的类型。
BASE_CLASS则用来指定基类的类型。它可以是任何非模板的容器。如CObList0.,CPtrList,CPtrArray。
MFC容器类支持的对象中,有两种需要特别说明:
一是Ob,表示派生自CObject的任何对象。MFC提供CObList,CObArray两种类。
二是Ptr,表示对象指针。MFC提供CPtrList,CPtrArray两种类。
绝大部分的MFC类,以及自己写的类都要从CObject派生下来,因为当一个类派生自CObject时,它也就继承了许多重要的性质,它至少提供两个机能:IsKindOf和IsSerialzable.
IsKindOf它是判断一个对象是不是某个类。它是依赖于CRuntimeClass。
boolCObject::IsKindOf(constCRuntimeClass*pClass)const
{
CRuntimeClass*pClassThis=GetRuntimeClass();
returnpClassThis->IsDerivedFrom(pClass);
}
boolCRuntimeClass::IsDerived(cosntCRuntimeClass*pBaseClass)const
{
constCRuntimeClass*pClassThis=this;
whiel(pClassThis)
{
if(pClassThis==pBaseClass)
returntrue;
pClassThis=pClassThis->pBaseClass;
}
returnfalse;
}
IsSerializable函数用以判断一个类是否可以Serialize,这主要通过判断CRuntimeClass的schema成员是否为0xFFFF.
boolCObject::IsSerialize()const
{
return(GetRuntimeClass()->m_wSchema!=0xffff);
}
CObject有一个虚函数Serialize,每一个希望具备serialize功能的类都需要重写这个函数。
DYNCREATE/DYNCREATE/SERIAL分别在CRuntimeClass所组成的类型型录中填写不同的记录。它们分别对应三个不同等级。
DYNAMIC仅具备动态类型识别。
DYNCREATE包括DYNAMIC同时还具备动态创建。
SERIAL包括DYNCREATE,还包括Serialize.
CArchive类管理文件缓冲区。它是Serialize的对象。CArchive针对许多C++数据类型,windows数据类型以及CObject派生类定义了operator<<和operator>>重载运算符。正因为如此,可以将各种类型的数据读出或写入CArchive。一个自定义的C++类如果想要有Serialization机制,就得直接或间接派生自CObject。为的是从CObject派生下列三个运算符:
_AFX_INLINECArchive&AFXAPIoperator<<(CArchive&ar,constCObject*pOb);
_AFX_INLINECArchive&AFXAPIoperator>>(CArchive&ar,CObject*&2pOb);
_AFX_INLINECArchive&AFXAPIoperator>>(CArchive&ar,constCObject*&pOb);
一个类如果希望有Serialization机制,它的第二要件就是使用SERIAL宏。
这个宏包含DYNCRETE宏,比DYNCREATE多了个:
friendCArchive&AFXAPIoperator>>
(CArchive&ar,class_name*&pOb);
在定义处增添了:
CArchive&AFXAPIoperator>>(CArchive&ar,class_name*&pOb)/
{/
pOb=(class_name*)ar.ReadObject(RUNTIME_CLASS(class_name));/
returnar;/
}
此处只改写了CObject::operator>>而没有改写operator<<,原因是WriteObject并不需要CRuntimeClass信息。但ReadObject需要,因为在读完文件之后还要进行动态创建操作。
前面就提到过CObject会抽象类且它没有基类,因此它需要特殊处理。
当多个视图显示同一个文档,为了保持各个视图操作的文档内容的一致性,需要以消息通知使用同一份文档的其他视图,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。
分享到:
相关推荐
总的来说,"深入浅出MFC"的学习资源可以帮助开发者从基础到高级全面了解MFC,通过实例和笔记加深理解,从而更高效地开发Windows应用程序。无论是初学者还是有一定经验的程序员,都能从中受益,提升自己的MFC编程能力...
《MFC深入详解》是C++开发者在学习微软基础类库(Microsoft Foundation Classes)时的一本重要参考书籍,由孙鑫撰写。MFC是微软为Windows操作系统提供的一个C++类库,它使得开发者能够更容易地使用Windows API进行...
MFC(Microsoft Foundation...总之,MFC学习代码和笔记对于希望深入理解和掌握Windows桌面应用程序开发的程序员来说,是一份不可多得的学习材料。通过学习和实践,可以提升编程技能,更好地驾驭MFC这一强大的开发工具。
这篇“学习MFC的视频笔记”显然是针对想要了解或深入学习MFC的初学者设计的,提供了视频教程的笔记内容,旨在帮助初学者快速入门。 1. **MFC基础**:MFC的核心是它的框架,它包括了各种C++类,如CWinApp、CWnd、...
2. 文档/视图模型:MFC采用文档/视图(Document/View)设计模式,文档存储数据,视图负责显示和编辑数据,框架窗口(Frame Window)作为容器管理视图。 3. 对话框与控件:MFC提供了对话框类(CDialog)和各种标准...
MFC中的核心设计是文档/视图(Document/View)架构,这是一种分离数据(文档)和显示(视图)的设计模式。文档类(CDocument)存储数据,视图类(CView)负责数据的显示和用户交互。框架负责文档和视图之间的通信,...
5. **day08.txt**:第八天的笔记或许介绍了文件操作和数据存储,MFС通过CFile类支持文件的读写,同时,对于结构化数据,MFС提供了CDocument和CDocument派生类来管理。 6. **day06.txt**:第六天可能讲解了事件...
3. **文档/视图架构**(Document/View Architecture):这是MFC设计模式的一部分,文档类(CDocument)存储数据,视图类(CView)负责数据的显示和编辑。这种分离允许多个视图同时显示同一份文档,支持多种查看方式...
MFC的核心设计之一是文档/视图(Document/View)架构,其中文档存储数据,视图负责显示和编辑这些数据,框架窗口(Frame Window)则管理文档和视图的交互。这种架构允许开发者分离数据逻辑与用户界面,提高了代码的...
### VC++ MFC 学习笔记知识点概览 #### 一、Windows程序内部运行原理 - **WinMain函数**:这是Windows程序的入口点。它接收四个参数:`HINSTANCE`, `HINSTANCE`, `LPSTR`, 和 `int`。这些参数分别代表当前实例句柄...
本学习笔记主要聚焦于Microsoft Foundation Classes (MFC)的深入理解和应用,MFC是微软为Visual C++开发的一个类库,它为Windows应用程序开发提供了强大的支持。MFC将Windows API封装成易于使用的C++类,使得开发者...
**文件列表解析:** "2007 VC++ MFC复习Beta版——加强理解Graduate精髓.doc" 这个文件很可能是文档形式的教程或笔记,涵盖了作者对2007年时MFC的深入理解和学习经验,包括可能的编程实例、最佳实践、问题解答等。...
2. **MFC架构**:MFC采用的是文档/视图(Document/View)架构,其中文档存储数据,视图负责显示数据,而框架窗口(Frame Window)管理用户界面。理解和掌握这个架构有助于你组织复杂的UI逻辑。 3. **消息映射**:...
在这个主题中,我们将深入探讨MFC中如何实现不同窗口之间的数据交换和事件传递。 首先,我们来看一下标题“多窗口之间的通信”。在MFC中,窗口通常由CWnd类或其派生类表示。当有多个窗口存在时,可能需要在它们之间...