1、,1,MFC程序中的文档视结构,2,1、文档读写2、文档视结构,3,1、文档读写,文档读写序列化(serialization):对象是可以连续的,将这个在磁盘上保存和恢复对象的过程称为序列化与数据库的区别:序列化不能代替数据库系统,所有与文档有关系的对象都可以从一个磁盘文件中顺序读写,而不能随机访问磁盘文件中的对象,4,如果不采用MFC的功能,对文档数据进行读写操作,应当怎么做MFC的CFile类的对象代表磁盘文件,5,如果你的程序不直接操作磁盘文件,则可以通过CArchive归档对象进行,6,MFC应用程序由程序框架管理CFile对象和CArchive对象,当执行File Open和File
2、 Save命令时,应用程序框架会调用文档类的Serialize函数我们需要做的是在Serialize函数中:将需要保存的数据存入到CArchive对象将需要读取的数据从CArchive对象载入文档的全部对象存在一个文件中,不能单独存取,7,简单MFC类对象的读写MFC中的类支持串行化在Doc类中只要简单操作进行读写,8,使类成为可串行化的类:直接或间接从CObject类派生出一个派生类在类的声明中包含宏:DECLARE_SERIAL(类名)在类的实现中包含宏:IMPLEMENT_SERIAL(类名,基类名,版本模式号)重载基本类的Serialize函数,并串行化派生类的数据成员添加一个没有参数
3、的构造函数在派生类的Serialize( )函数中调用基类的Serialize( )函数,如果基类是CObject,则不必调用,9,集合类对象的读写(CArray, CMap, CList)集合类的基类是CObject,都支持串行化其他类都应声明DECLARE_SERIAL和IMPLEMENT_SERIAL,支持串行化,10,2、文档视结构,文档视结构概念单文档应用程序多文档应用程序切分窗口和多视图多文档类型模板结构,11,一般情况下,采用文档/视结构的应用程序至少应由以下对象组成:应用程序是一个CWinApp派生对象,它充当全部应用程序的容器。应用程序沿消息映射网络分配消息给它的所有子程序。
4、框架窗口是一CFrmeWnd派生对象。文档是一个CDocument派生对象,它存储应用程序的数据,并把这些信息提供给应用程序的其余部分视窗是CView派生对象,它与其父框架窗口用户区对齐。视窗接受用户对应用程序的输入并显示相关联的文档数据。,12,在文档/视方式中,对象的建立是由文档模板来管理的,它是CDocTemplate派生对象,建立并维护框架窗口、文档及视模板维护它们之间的关系。这种文档/视结构在开发大型软件项目时特别有用MFC调用命令处理程序以响应发生在应用程序中的事件。命令发送的优先级是:活动的视图-框架窗口-文档-应用程序-默认窗口过程(DefWindowsProc),13,无文档
5、视结构基于对话框的应用基于单文档(SDI)基于多文档(MDI)带有文档视结构的应用基于对话框的应用基于单文档(SDI)基于多文档(MDI),14,单文档应用程序,简单的文档视结构,15,文档保存数据:在文档类中添加公有数据成员CDocument:UpdateAllViews更新所有的视图对象当文档的UpdateAllViews被调用时和此文档相关的所有视的OnUpdate都会被调用 视图显示和编辑数据:CView:GetDocument得到对应的文档对象在视图的OnDraw函数中使用文档类的数据成员,其它函数改变编辑文档类的数据成员,16,单文档应用程序启动(1) Windows将程序装入内存
6、构造全局对象:包括theAppWindows调用全局函数AfxWinMain函数AfxWinMain自动搜索CWinApp派生类的唯一实例AfxWinMain调用CWinApp派生类的InitInstance函数,InitInstance函数中启动文档的载入以及主框架和视口窗口的显示AfxWinMain调用theApp的Run函数,启动窗口消息和命令消息的分发处理过程,17,单文档应用程序启动(2) 应用程序对象是全局对象,已创建文档、视图和框架对象在应用程序框架需要时动态创建创建什么样的文档、视图和框架对象由文档模板来决定(多文档),18,单文档应用程序启动(3) InitInstance函
7、数调用ProcessShellCommand函数:来决定现在是新建文件还是打开文件CCommandLineInfo cmdInfo; cmdInfo.m_nShellCommand = CCommandLineInfo:FileOpen; cmdInfo.m_strFileName = sWorkDir+default.set; ParseCommandLine(cmdInfo); if(!ProcessShellCommand(cmdInfo) return FALSE; 创建新文档:CWinApp:OnFileNew打开文档:CWinApp:OnFileOpen,19,单文档应用程序启动(
8、4)-创建新文档构造文档对象,但不从磁盘中读数据构造主框架对象,创建主框架窗口构造视图对象,创建视图窗口建立文档、主框架和视图对象之间相互关系调用文档对象的OnNewDocument,其中调用DeleteContents函数(清空文档,确保文档是空的):文档对象已经建立,但可以在此对文档类中的成员初始化调用框架对象ActivateFrame函数,显示框架窗口和视图窗口,20,单文档应用程序启动(5)打开文档构造文档对象;构造主框架对象,创建主框架窗口;构造视图对象,创建视图窗口;建立文档、主框架和视图对象之间相互关系调用文档对象的OnOpenDocument;其中调用DeleteContent
9、s函数并创建一个装入数据的Carchive对象;调用文档的Serialize函数调用框架对象ActivateFrame函数,显示框架窗口和视图窗口程序具有拖放功能:InitInstanse函数中加入:EnableShellOpen;RegisterShellFileTypes;CWnd-DragAcceptFiles,21,程序运行中新建文档调用已经存在的文档对象OnNewDocument,其中调用DeleteContents函数;文档对象已经建立,但可以在此对文档类中的成员初始化;或对文档对象中的指针成员重新初始化调用视图的OnInitialUpdate函数虚函数,当视图对象第一次创建时,在
10、这个函数中完成相应的初始化。,22,程序运行中打开文档调用CWinApp:OnFileOpen提示用户选择一个文件调用已经存在的文档对象OnOpenDocument,其中调用DeleteContents函数并创建一个装入数据的CArchive对象;调用文档的Serialize函数调用视图的OnInitialUpdate函数,23,程序运行中保存文档:File Save和File Save As菜单项已映射到CDocument类的OnSaveDocument和OnFileSaveAs两个函数应用程序框架将调用文档的Serialize函数文档的“脏”标志:m_bModifiedSetModifie
11、dFlagIsModified,24,SDI程序调用命令处理程序以响应发生在应用程序中的事件。命令发送的优先级是:活动的视图-文档-框架窗口-应用程序-默认窗口过程(DefWindowsProc),25,多文档应用程序,多文档应用程序启动(1) 与单文档应用程序的启动步骤基本一样主窗口由InitInstanse创建并显示在InitInstance函数中,使用的文档模板不一样,使得多文档应用程序可以同时有多个子窗口(文档对象),每个子窗口都与一个文档对象和一个或多个视图对象相连接多文档模板对象记录了所有从该模板创建的活动的文档对象MDI与SDI不同的是:MDI应用程序可以使用多种文档类型,并允许
12、多个文档对象同时存在,26,程序启动或运行中创建新文档(每个文档包括子框架对象,文档对象和视对象): 构造文档类对象构造子框架对象,创建子窗口窗口构造视图对象,创建视图窗口建立文档、主框架和视图对象之间相互关系调用文档对象的OnNewDocument,其中调用DeleteContents函数:文档对象已经建立,但可以在此对文档类中的成员初始化调用视图对象的OnInitialUpdate调用框架对象ActivateFrame函数,显示框架窗口和视图窗口,27,程序启动或运行中打开文档(每个文档包括子框架对象,文档对象和视对象): 构造文档类对象;构造子框架对象,创建子窗口窗口;构造视图对象,创建
13、视图窗口建立文档、主框架和视图对象之间相互关系调用文档对象的OnOpenDocument,其中调用DeleteContents函数:其中调用DeleteContents函数并创建一个装入数据的Carchive对象;调用文档的Serialize函数调用视图对象的OnInitialUpdate调用框架对象ActivateFrame函数,显示框架窗口和视图窗口,28,程序运行中保存文档:File Save和File Save As菜单项已映射到CDocument类的OnSaveDocument和OnFileSaveAs两个函数应用程序框架将调用文档的Serialize函数文档的“脏”标志:m_bMo
14、difiedSetModifiedFlagIsModified,29,MDI程序调用命令处理程序以响应发生在应用程序中的事件。命令发送的优先级是:活动的视图-文档-子框架窗口-应用程序-主框架窗口-默认窗口过程(DefWindowsProc)(不活动的视不响应命令),30,切分窗口和多视图,一个文档可以有多个视:SDI,切分(主)窗口,单一视图类SDI,切分(主)窗口,多视图类SDI,无切分窗口,多视图类MDI,无切分窗口,单一视图类MDI,无切分窗口,多视图类MDI,切分子窗口,单一视图类或多视图类,31,切分窗口:CSplitterWnd单个视图类的动态切分:AppWizard中Step4
15、中Advanced OptionsMainFrame:OnCreateClient多个视图类的静态切分:AppWizard中Step4中Advanced Options建立一个新View类MainFrame:OnCreateClient中显示两个视窗口;两个视窗口与同一个文档对象相连,32,由程序命令切换视图类在应用程序启动构造一个视图类对象,创建视图窗口并显示视图切换时:如视图类对象未构造:构造、创建一个窗口并加入到文档类管理的一个视列表中将该视图窗口作为当前的视图窗口并显示原视图窗口不显示需要进行一些状态保存设置工作程序运行时打开或新建文档SDI或MDI一样,视图只与文档有关视图的销毁由文
16、档类对象完成,33,多文档类型模板结构,建立了应用类、文档类、视图类、框架窗口类之间的关系:通过文档模板,我们可以知道在创建或打开一个文档时,需要用什么样的视图、框架窗口来显示它。对象的动态构造解决类用户复杂的编程:这是因为文档模板保存了文档和对应的视图和框架窗口的CRuntimeClass对象的指针每个从CObject中派生的类都有一个 CRuntimeClass对象同它关联以完成在运行时得到类实例的信息或者是它的基类,34,如果应用程序需要处理多种类型的文档,并且何时打开何种文档均需程序员手工控制,此时,程序员必须对文档模板进行编程。如何根据自己的要求来选择文档模板,及相应的视和文档。分别
17、建立两套文档模板,分别对应着两套文档模板资源,两套框架窗口,两套文档和两套视,分别用于两种不同数据的存放和显示。程序可以根据用户选择的文件名来分别处理这两种数据。,35,添加新文档的步骤:创建新的文档类和视图类创建一个文档菜单创建文档菜单对应的字符串表在CWinApp:InitInstance()中注册新的文档模板,36,应用程序、文档模板、文档、框架窗口及视窗对象间的关系 :,37,每个应用程序可以有多个文档模板,标示不同的文档类型新建文档模板对象加入到应用程序框架中:AddDocTemplate()以后新建文档时将可选择地建立某一类型的文档打开文档时应用程序框架将根据文档信息用某一文档类型
18、的模板打开,38,MDI应用程序可以处理多个文档类型,即多个文档模板;每个模板又可以有多个文档;每个文档又可以多视显示。为管理方便,上一级往往保留了下一级的指针列表。每个应用程序对象保存了文档模板对象每个文档模板对象保存了使用该文档模板创建的活动的文档对象每个文档对象保存了一个视列表,39,MDI中的指针列表,40,每个应用程序类(CWinApp的派生类)都保留并维护了一份所有文档模板的指针列表,这是一个链表结构: 应用程序为所要支持的每个文档类型动态分配一个CMultiDocTemplateGetFirstDocTemplatePostion获得应用程序注册的第一个文档模板的位置 GetNe
19、xtDocTemplate函数获得下一个CDocTemplate对象指针通过这两个函数,应用程序可以遍历整个文档模板列表;如果被检索的文档模板是模板列表中的最后一个,则pos参数被置为NULL,41,一个文档模板可以有多个文档,每个文档模板都保留并维护了一个所有对应文档的指针列表:应用程序可以用GetFirstDocPosition函数获得与文档模板相关的文档集合中第一个文档的位置并用POSITION值作为GetNextDoc的参数来重复遍历与模板相关的文档列表如果列表为空,则pos被置为NULL,42,一个文档可以有多个视。每一个文档都保留并维护一个所有相关视的列表:GetFirstView
20、Position返回与调用文档相联系的视的列表中的第一个视的位置GetNextView返回指定位置的视,并将rPositon的值置为列表中下一个视的POSITION值如果找到的视为列表中的最后一个视,则将rPosition置为NULL.,43,各程序框架中类之间的存取关系,44,各类之间的存取关系(0) AfxGetApp !(1) GetFirstDocTemplatePostion GetNextDocTemplate (2) GetFirstDocPosition GetNextDoc(3) GetDocTemplate(4) GetFirstViewPosition GetNextView(5) GetDocument,45,各类之间的存取关系(6) GetActiveDocument (7) GetActiveView(8) GetActiveFrame(9) GetMDIFrame (10) AfxGetMainWnd,