单文档与多文档解析课件.ppt

上传人:小飞机 文档编号:1552702 上传时间:2022-12-04 格式:PPT 页数:51 大小:269KB
返回 下载 相关 举报
单文档与多文档解析课件.ppt_第1页
第1页 / 共51页
单文档与多文档解析课件.ppt_第2页
第2页 / 共51页
单文档与多文档解析课件.ppt_第3页
第3页 / 共51页
单文档与多文档解析课件.ppt_第4页
第4页 / 共51页
单文档与多文档解析课件.ppt_第5页
第5页 / 共51页
点击查看更多>>
资源描述

《单文档与多文档解析课件.ppt》由会员分享,可在线阅读,更多相关《单文档与多文档解析课件.ppt(51页珍藏版)》请在三一办公上搜索。

1、1,第 11章 单文档与多文档,本章主要介绍Visual C+中的文档/视图结构的工作机制,2,11.1 概述,3,11.1.1单文档界面与多文档界面,VC的MFC库支持三种不同的应用程序,SDI的应用程序只有一个窗口,MDI的应用程序每次可以读写多个文件或文档,可同时对多个文档进行操作,可以有多个子窗口,主要差别,在创建SDI界面的应用程序时,不生成CChildFrame类,CMainFrame类的基类为CFrameWnd,在创建MDI界面的应用程序时,CMainFrame类的基类为CMDIFrameWnd,4,由于每一个文档可以有多个视图,但每个视图只能对应于一个确定的文档,多文档程序需要

2、解决的问题仅仅是多个文档的数据管理方法的问题,多文档程序,最初的文档模板只支持主窗口,但每次打开一个新文档时都调用CDocument的函数OnNewDocument,建立一个由CMDIChildWnd派生的新的MDI子窗口,这些窗口中保存着各种已打开的文档,所有的细节都由MFC库处理,视图是文档的不同表现形式,一个*.html语言的文件,在浏览器里和在记事本中打开的表现形式是不同的但它们操作的是同一个文件这就是一个文档对应两视图,5,11.1.2 文档/视图结构,在文档/视图结构中,6,文档/视图结构的工作机制,视图通过GetDocument成员函数获得指向相关联的文档对象的指针,通过该指针调

3、用文档类的成员函数来从文档中读取数据,视图把数据显示于计算机屏幕上,用户通过与视图的交互来查看数据并对数据进行修改,视图通过相关联的文档类的成员函数将经过修改的数据传递给文档对象,文档对象获得修改过的数据之后,对其进行必要的修改,最后保存到永久介质(如磁盘文件)中,7,SDI文档/视图应用程序示意图,8,11.1.3 SDI程序中文档、视图对象的创建过程,SDI程序中框架窗口、文档和视图的创建是在应用程序对象的InitInstance()成员函数中通过文档模板类完成的:CSingleDocTemplate * pDocTemplate; /创建单文档模板类对象pDocTemplate = ne

4、w CSingleDocTemplate(IDR_MAINFRAME, RUNTIME_CLASS (CMyDoc),/CMyDoc是应用程序中的文档类 RUNTIME_CLASS (CMainFrame),/CMainFrame是应用程序中的框架窗口 RUNTIME_CLASS (CMyView) );/CMyView是应用程序中的视图类AddDocTemplate(pDocTemplate); /加载文档模板类对象到文档模板列表CCommandLineInfo cmdInfo;ParseCommandLine(cmdInfo); /初始化CCommandLineInfo对象if(! Pro

5、cessShellCommand(cmdInfo) /据对象中的信息启动程序 return FALSE;m_pMainWnd - ShowWindow(SW_SHOW);m_pMainWnd - UpdateWindow();/显示和更新窗口,9,11.1.4 SDI程序的消息传递过程,当用户选择了菜单项,单击了快捷键或工具条按钮,系统就会发送WM_COMMAND消息。框架窗口实际上是大多数WM_COMMAND消息的接受者,但WM_COMMAND消息还可以在视图、文档,甚至应用程序类中被处理。,10,11.2 Doc/View框架的主要成员,Doc/View框架虽然可以调用成百上千个不同的类,

6、但是核心类只有五个:CWinAppCDocumentCViewCDocTemplateCFrameWnd,11,11.2.1 CWinApp 类,CWinApp类代表主程序,CWinApp本身是不可见的,它负责维护进程的启动、终止、消息循环、命令行参数、资源管理,成员描述m_pszAppName应用程序名M_lpCmdLine命令行参数M_pMainWnd应用程序主窗口指针M_pszExeName可执行文件名M_pszProfileName配置INI文件名M_pszRegistrKey配置注册表主键值LoadCursor加载光标资源LoadIcon加载图标资源,部分主要成员,12,11.2.2

7、 CDocument类,13,最常用的是SetModifiedFlag()和UpdateAllViews()。文档内容被修改后,一般要调用SetModifiedFlag()来设定一个标志。UpdateAllView()刷新所有和文档关联的视图。实际上该函数调用各个视图类的OnUpdate()函数。这样做可以保证各个视图之间的同步。,14,用户可通过函数GetFirstViewPosition()和GetNextView()得到和文档关联的视图的指针,代码如下:POSITION pos = GetFirstViewPosition(); /得到视图列表头的位置While(pos != NULL)

8、 CView *pView = GetNextView(pos);/获得视图列表中的视图指针CDocument类在现在流行的MVC(Modal、View、Control)设计模式中相当于其中的Modal,表示抽象数据模型。文档最主要的功能如下:l 打开保存文档l 维护文档相关的视图列表l 维护文档修改标志l 通过电子邮件发送文档 用户修改文档数据时,调用SetModifiedFlag方法来标志数据被更改过。当程序关闭该文档关联的最后一个视图的时候,文档会自动提示你保存修改。,15,从CDocument类派生新的文档类的一般过程如下:为每一个文档类型从CDocument类派生一个相应的文档类。为

9、文档类添加成员变量,这些变量主要用来保存文档的数据,并使其它的对象(如视图对象)可以访问这些成员变量,从而实现文档和视图的相互搭配使用。重载Serialize成员函数,实现文档数据的串行化。,无论是保存文档或是打开文档,应用程序都是通过调用文档类的Serialize串行化成员函数来完成操作的。因此,在大多数情况下,我们都需要重载Serialize成员函数。Serialize成员函数带有一个CArchive类型的参数,这是一个与所打开的文件相关联的对象。一般情况下,总是使用CArchive对象来保存和打开文档。,16,CArchive对象是单向的,只用于保存或读取两者之一,不能通过同一个CArc

10、hive对象既保存又读取文档。 在框架创建CArchive对象时,已根据用户选择的是 “保存” ( “另存为” )还是 “打开” 来设置了CArchive对象的类型,我们可以使用CArchive类的成员函数IsStoring来检索当前CArchive对象的类型,从而得知用户所期望的操作是保存还是读取,执行不同的操作。,17,11.2.3 CView类,视图类(CView)是从CWnd类下派生的,视图类具有CWnd的所有功能如:创建、移动、显示和隐藏窗口等。CView类可以接收任何Windows消息,而CDocument类则不行,IsSelected():确定文档是否被选中OnScroll():

11、当用户滚动时,CView的响应OnInitialUpdate():在类第一次构造后由MFC调用OnDraw():由MFC调用发出文档到设备描述表OnUpdate():由MFC调用对文档的修改进行响应OnPrepareDC():在调用OnDraw()前允许修改设备描述表由MFC调用,CView主要虚拟方法,18,CView类中最常用的是OnDraw函数,该函数在屏幕发生变化或因为焦点的变化需要重绘时调用,没有该函数,就不可能在程序的切换后保证屏幕的正确显示。 注意: 尽量不要在OnDraw之外的函数调用绘图方法,那些方法不会在视图需要重新绘制的时候被自动调用。 若想在数据更新的时强制视图更新,可

12、调用Invalidate方法和UpdateWindow方法来实现。,19,CEditView:简单的文本编辑器,类似NotepadCListView:基于列表的视图,类似文件夹浏览CTreeView:基于树状控件的视图,类似文件浏览左侧的树状结构CRichEditView:支持多种字体、OLE和RTF格式的高级编辑器CScrollView:支持滚动条的视图CFormView:窗体视图,支持在上边使用对话框控件CRecordView:连接到ODBC数据库的视图CDaoRecordView:连接到DAO数据库的视图,CView的子类,20,11.2.4 CDocTemplate类,文档模板类在应用

13、程序中有着非常重要的作用,是它将原本独立的文档、视图和框架窗口对象联系在一起,文档模板类负责具体的关联文档、视图、框架的创建,21,在VC+中,文档对象、与文档对象相关联的视图对象以及为视图对象提供显示的框架窗口都是由文档模板创建的。 每一种文档类型都有一种文档模板与之相对应,文档模板负责创建和管理该文档类型的所有文档。文档模板的构造函数的原型如下:CDocTemplate(UINT nIDResource, /与文档一同使用的各种资源的资源标识符CRuntimeClass* pDocClass,/ 指向文档派生文档类的对象的指针CRuntimeClass* pFrameClass, /框架类

14、的派生框架类的对象指针CRuntimeClass* pViewClass /指向CView的派生视图类的对象指针 ),在SDI应用程序中只有一个文档模板对象,而MDI应用程序需要针对不同类型的文档定义不同的文档模板对象。,22,当前位置被访问的位置访问方法文档视图GetFirstViewPositionGetNextView文档模板GetDocTemplate视图文档GetDocument视图框架GetParentFrame框架视图GetActiveView框架文档GetActiveDocumentMDI主框架MDI子框架MDIGetActiveMDI子框架MDI主框架GetParentFra

15、me任何位置应用程序AfxGetApp任何位置主框架AfxGetMainWnd,Doc/View结构的五个基本成员经常需要互相访问,假设某个视图想要获得文档,或某个框架需要获得活动视图,可以通过此表提供的方法进行解决,23,11.2.5 CFrameWnd类,CFrameWnd类在Doc/View结构中起着举足轻重的作用。 框架窗口维护了很多幕后的工作,例如工具条、菜单、状态条的显示、更新,视图的位置和显示,其它可停靠空间的停靠和动态尺寸调整。许多默认为MFC应用程序应该具备的基本功能都是CframeWnd类在完成,24,11.3文档操作中的一些重要概念,串行化处理,文档操作,文档的消息映射,

16、文档消息传递,文件打开,文件保存,25,11.3.1 串行化处理,串行化:将对象写入字节流和从字节流恢复对象的操作 串行化除了可以使用文件保存对象之外,还可以通过网络、串口传输对象,因此使用字节流。串行化代码如下:void CMDIDoc:Serialize(CArchive& ar)if (ar.IsStoring()/ TODO: add storing code hereelse/ TODO: add loading code here,26,使用串行化的好处是不需要重载文件打开、文件保存之类的方法,MFC框架会自动完成这些任务,并自动调用文档类的Serialize方法来完成串行化过程。

17、 如果文档的抽象数据只有一个字符串,那么你只需要在Serialize中添加相应语句就可以完成串行化过程。 如果不使用MFC提供的串行化框架,那么就需要重载一些函数,来获取文件名,然后自己来读写文件完成对象的串行化。,27,在进行串行化处理时,通常是通过CArchive(档案)类来完成的,成员描述WriteString写入字符串ReadString读取字符串ReadClass读取类信息WriteClass写入类信息Close关闭档案GetObjectSchema读取对象版本号SetObjectSchema设置对象版本号M_pDocument使用该档案的文档Read读取字节内容Write写入字节内

18、容GetFile获取底层的CFile对象operator从流中读取基本类型IsStoring是否处于保存状态Flush将缓冲中的数据强制写入流中Abort在不发送异常的情况下关闭档案ReadObject读取串行化对象WriteObject写入串行化对象,CArchive类的常用成员,28,若使用串行化,可以不关心文件打开关闭的具体过程,只需要完善Serialize方法即可,但是很多应用程序都希望来亲自控制用户打开保存文件的过程,缺省处理方法CWinApp:OnFileOpenCWinApp:OpenDocumentFileCDocTemplate:OpenDocumentFileCDocume

19、nt:OnOpenDocumentCDocument:SerializeCDocument:OnFileSave/OnFileSaveAsCDocument:OnSaveDocument,文件打开或保存时重载的某一个缺省处理方法,29,11.3.2 消息映射,使用ClassWizard来添加消息映射,但有时,ClassWizard不支持某些类的消息映射,需自己添加一些自定义的消息,这时都需要手工添加消息映射代码,数组中存储的信息,消息应用于的控件ID,或者ID范围所处理的消息消息所传递的参数消息所期望的返回值,消息映射本质上就是一个数组,MFC使用该数组来确定消息传递时具体要传递给哪一个函数,

20、30,当MFC收到消息后,便自动确定目标窗口和相应的MFC类的实例。然后它便搜索窗口的消息映射寻找匹配的项。若窗口中没有处理该消息的处理程序,MFC便进一步搜索窗口的父类。如果父类也没有找到处理该消息的函数,MFC便将消息传递给该窗口的原窗口过程,31,在消息映射的时候,仅仅靠ClassWizard生成的宏是不够的,有时需要向已有的消息映射添加自己的宏,但所添加的宏一定要放在ClassWizard的特殊注释之外。 以下是由AppWizard产生的默认MDI视图的消息映射,另外添加了一个菜单项的处理和一个WM_ERASEBKGND消息的映射:,BEGIN_MESSAGE_MAP(CMDIView

21、, CView) /AFX_MSG_MAP(CMDIView) ON_COMMAND(ID_OPER_TEST, OnOperTest) ON_UPDATE_COMMAND_UI(ID_OPER_TEST, OnUpdateOperTest) ON_WM_ERASEBKGND() /AFX_MSG_MAP / Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView:OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView:OnFilePrint) ON_COMMAND(ID_FILE_P

22、RINT_PREVIEW, CView:OnFilePrintPreview)END_MESSAGE_MAP(),位于AFX_MSG_MAP之间的宏来自ClassWizard,特定宏,ON_COMMAND是通用宏,32,在第二个AFX_MSG_MAP之后,可以添加自己的消息映射,ClassWizard不检查这里,这里的消息映射不会出现在ClassWizard中的,33,11.3.3 消息传递,由于用户可以在很多MFC类中映射同一个消息,如可以在文档和视图中同时映射打开文件的消息,这样就需要消息有明确的来源,也有明确的接收者,因此需要判断消息传递的顺序。,当前视图当前文档与当前视图/文档关联的文

23、档模板子框架窗口(只有MDI有该步骤)主框架窗口应用程序对象,34,11.4 SDI编程实例,【例11-1】在主窗口中央显示一文本“您好, 单文档界面的例程!”。单击“改变显示文本”菜单项,可弹出一个对话框,通过此对话框可改变主窗口中的显示文本内容,35,(1) 创建工程文件和对话框资源,创建一个单文档工程文件MySdi,然后添加对话框资源,(2) 为CMySdiDoc类添加成员变量,在CMySdiDoc类的定义中增加如下的代码: CString m_str;,用以存放字符串,36,(3) 文档变量初始化,打开CMySdiDoc.cpp文件,在 OnNewDocument成员函数加入以下代码:

24、BOOL CMySdiDoc:OnNewDocument()if (!CDocument:OnNewDocument()return FALSE;m_str=“您好,单文档界面的例程!”/初始化成员变量return TRUE;,37,(4) 视图的输出,MySdi程序视图类CMySdiView类的OnDraw成员函数:void CMySdiView:OnDraw(CDC* pDC) CMySdiDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); CRect rectClient; GetClientRect(rectClient);/ 获取当前客户区的

25、指针 CSize sizeClient=rectClient.Size();/ 获取当前客户区的大小 CString str=pDoc-m_str;/ 从文件中读取数据 CSize sizeTextExtent=pDC-GetTextExtent(str);/ 用新选定的字体绘制字符串 pDC-TextOut(sizeClient.cx-sizeTextExtent.cx)/2,(sizeClient.cy-sizeTextExtent.cy)/2,str);调用GetDocument()得到文档类的指针,将文档对象成员变量复制到字符串str中,调用TextOut()将m_str的内容显示到框

26、架窗口中的视图中。,38,(5) 文档串行化,在 “编辑” 菜单中添加菜单项“改变显示文本” (ID_EDIT_CHANGETEXT )。单击此菜单项可以将将对视图中显示文本所做的修改保存到一个磁盘文件中,具体的实现方法如下:,void CMySdiDoc:OnEditChangetext() CDlgInput inputDlg;/创建一个 CInputDlg类的对象inputDlg if(inputDlg.DoModal()=IDOK)/显示对话框 m_str=inputDlg.m_input;/获取输入的字符串UpdateAllViews(NULL);/更新视图 ,39,为了在CMySd

27、iDoc类中定义对话框类CDlgInput对象,还必须在MySdiDoc.cpp文件中加入CDlgInput类的头文件DlgInput.h,代码如下:#include DlgInput.h/加入头文件,为了把这些修改保存到磁盘文件中,并在需要时可以打开所保存的磁盘文件读取文档,需要重载CExampleDoc类的Serialize函数来完成串行化。重载后的Serialize函数的代码如下:void CMySdiDoc:Serialize(CArchive/读取文档内容,40,11.5 MDI编程实例,【例16-2】创建多文档的应用程序,可以打开两种类型的文档。MyMdi1是系统默认生成的文档(可

28、以打印)。MyMdi21是另一个用户添加的文档类型(不允许打印),在程序的窗口中显示“您好, 多文档界面的例程!”, 注意如果活动文档的 类型改变,则菜单的 “编辑”项的子菜单不 同,工具条上的“打印” 按钮的激活状态也不 同,41,(1) 创建MDI工程文件 创建MyMdi工程文件,在Step 4 of 6 的窗口中,单击Advanced按钮,在File extention对话框中加入mmd,完成后的应用程序的文件将使用“.mmd”为扩展名,文件过滤器域显示为“MyMdi文件(*.mmb)”,在Step 6 of 6 的对话框中,为CMyMdiView类设置基类为CEditView。,42,

29、(2)创建第二种文档和视图类View ClassWizard Class Info Add Class New,43,(3) 创建资源,在Resource.h文件中,手工加入下列代码:#define IDR_MYMDITYPE2135 这样就定义了第二类文档的文档、视图和框架窗口共同的资源ID,以后定义的菜单、文档模板等资源均可以使用此ID文档模板字符串的格式如下:nIDResource nnnnnnn,44,对于第一个文档,应用程序向导直接产生了一个文档模板,现在必须手工加入第二个资源模板字符串。具体的方法是:打开MyMdi.rc文件,首先找到如下代码:IDR_MYMDITYPE nMyMd

30、i nMyMdi nMyMdi 文件 (*.mmd) n.mmd nMyMdi.Document nMyMdi Document,45,在上面代码的后面加入:IDR_MYMDITYPE2 nMyMdi2 nMyMdi2 nMyMdi2 文件 (*.mm2) n.mm2 nMyMdi2.Document nMyMdi2 Document,类似第一个资源模板的格式,(3) 菜单、对话框资源,类似第一个例题,46,(4) 代码编辑(a) 创建文档模板类 本程序支持多种文档,在应用程序的InitInstance()函数中,需要定义新的文档模板的对象,在MyMdi.cpp中输入代码如下:BOOL CMy

31、MdiApp:InitInstance() CMultiDocTemplate* pDocTemplate2; pDocTemplate2 = new CMultiDocTemplate(IDR_MYMDITYPE2,RUNTIME_CLASS(CMyMdiDoc2), / MDI派生文档类的CRuntimeClass对象的指针RUNTIME_CLASS(CChildFrame), / MDI派生子框架类的CRuntimeClass对象的指针RUNTIME_CLASS(CMyMdiView2);/ 创建文档模板对象AddDocTemplate(pDocTemplate2);/将新模板添加到应用

32、程序的文档模板列表中,47,为使CMyMdiDoc2类和CMyMdiView2类在CMyMdiApp类中成为可识别的类,必须在MyMdiApp.cpp文件中加入CMyMdiDoc2类和CMyMdiView2类的说明头文件MyMdiDoc2.h和MyMdiView2.h/ MyMdiApp.cpp : implementation of the CMyMdiApp class#include MyMdiDoc2.h/加入头文件#include MyMdiView2.h,48,(b) 扩展CMyMdiDoc2类,添加成员变量:在类CMyMdiDoc2中增加Cstring类型的成员变量m_str,文

33、档变量初始化:为了能够在的二个文档中显示“您好, 多文档界面的例程!”,需在CMyMdiDoc2类的OnNewDocument()成员函数中为变量m_str赋初值。因此需添加下列代码: BOOL CMyMdiDoc2:OnNewDocument()if (!CDocument:OnNewDocument()return FALSE;m_str=您好, 多文档界面的例程!;return TRUE;,49,添加菜单处理函数: 在类CMyMdiDoc2中为“编辑”菜单中的菜单项 “改变显示文本” 添加消息处理函数OnEditChangeText(),加入代码如下:void CMyMdiDoc2:On

34、EditChangetext() / TODO: Add your command handler code here CDlgInput inputDlg;/创建一个CinputDlg类的对象inputDlg if( inputDlg.DoModal()=IDOK )/显示inputDlg模式对话框 m_str = inputDlg.m_input;/获取输入的字符串UpdateAllViews(NULL);/更新视图 为使CInputDlg类在CMyMdiDoc类中成为可识别的类,必须在MyMdiDoc2.cpp文件中加入CinputDlg类的说明头文件InputDlg.h/ MyMdiD

35、oc2.cpp : implementation of the CMyMdiDoc2 class#include DlgInput.h/加入头文件,50,文档串行化 :为了把对视图中显示文本的修改保存到磁盘文件中,并在需要时可以打开所保存的磁盘文件读取文档,必须重载CExampleDoc类的Serialize函数来完成串行化重载后的Serialize()函数的代码如下:/ CMyMdiDoc2 serializationvoid CMyMdiDoc2:Serialize(CArchive/读取文档内容,51,(c) 视图的输出,为将m_str的内容显示到视图的框架窗口中。需要在OnDraw()

36、函数中加入下列代码,注意下列代码的头两行与系统自动生成的代码的差异,需要按下列方式进行调整。void CMyMdiView2:OnDraw(CDC* pDC)CMyMdiDoc2* pDoc = (CMyMdiDoc2*)GetDocument();/得到文档对象指针ASSERT_VALID(pDoc);/ TODO: add draw code for native data hereCRect rectClient;/ 获取当前客户区的大小GetClientRect(rectClient); / 获取当前客户区的指针CSize sizeClient=rectClient.Size();/获取当前客户区的大小CString str=pDoc-m_str;/ 从文档对象中读取数据CSize sizeTextExtent=pDC-GetTextExtent(str);/ 用新选定的字体绘制字符串pDC-TextOut(sizeClient.cx-sizeTextExtent.cx)/2, (sizeClient.cy-sizeTextExtent.cy)/2,str); /输出文本在文件开始部分加入 : #include MyMdiDoc2.h,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号