1、1第第 11章章 单文档与多文档单文档与多文档 本章主要介绍本章主要介绍Visual C+Visual C+中的中的文档文档/视图结构的工作机制视图结构的工作机制 211.1 概述概述 311.1.1单文档界面与多文档界面单文档界面与多文档界面 VCVC的的MFCMFC库支库支持三种不同持三种不同的应用程序的应用程序单文档界面单文档界面(SDI)多文档界面多文档界面(MDI)基于对话框的应用程序基于对话框的应用程序SDI的应用程序的应用程序只有一个窗口只有一个窗口MDI的应用程序每次的应用程序每次可以读写多个文件或可以读写多个文件或文档,可同时对多个文档,可同时对多个文档进行操作,可以文档进行
2、操作,可以有多个子窗口有多个子窗口主主要要差差别别在创建在创建SDI界面的应用程序时,不生成界面的应用程序时,不生成CChildFrame类,类,CMainFrame类的基类类的基类为为CFrameWnd在创建在创建MDI界面的应用程序时,界面的应用程序时,CMainFrame类的基类为类的基类为CMDIFrameWnd使用使用AppWizard创建创建SDI和和MDI界面的应界面的应用程序的过程几乎完用程序的过程几乎完全一样全一样4由于每一个文档可以有多个视图,但由于每一个文档可以有多个视图,但每个视图只能对应于一个确定的文档每个视图只能对应于一个确定的文档多文档程序需要解决的问题仅仅是多多
3、文档程序需要解决的问题仅仅是多个文档的数据管理方法的问题个文档的数据管理方法的问题多文档程序,最初的文档模板只支持主窗口,但每次打开一多文档程序,最初的文档模板只支持主窗口,但每次打开一个新文档时都调用个新文档时都调用CDocument的函数的函数OnNewDocument,建,建立一个由立一个由CMDIChildWnd派生的新的派生的新的MDI子窗口,这些窗口子窗口,这些窗口中保存着各种已打开的文档,所有的细节都由中保存着各种已打开的文档,所有的细节都由MFC库处理库处理视图是文档的不同表现形式,一个视图是文档的不同表现形式,一个*.html语言的文件,在浏览器里和在记事本中打语言的文件,在
4、浏览器里和在记事本中打开的表现形式是不同的但它们操作的是同开的表现形式是不同的但它们操作的是同一个文件这就是一个文档对应两视图一个文件这就是一个文档对应两视图511.1.2 文档文档/视图结构视图结构 在在文档文档/视图视图结构中结构中对数据进行管理和维对数据进行管理和维护,数据保存在文档护,数据保存在文档类的成员变量中类的成员变量中文档类文档类通过串行化通过串行化的过程将数据保存的过程将数据保存到磁盘文件或数据库中到磁盘文件或数据库中文档类文档类还可处理来自如还可处理来自如菜单、工具栏按钮和加菜单、工具栏按钮和加速键的速键的WM_COMMANDWM_COMMAND消息消息除除WM_COMMA
5、NDWM_COMMAND外,文档外,文档不不能能处理其它的处理其它的WindowsWindows消息消息由此我们可由此我们可以看出,命以看出,命令消息可以令消息可以被多种对象被多种对象处理,这些处理,这些对象除了窗对象除了窗口和视图外口和视图外,还可以是,还可以是文档、文档文档、文档模板或应用模板或应用程序本身程序本身这一点与这一点与WindowsWindows消息消息和控件通知消息不同,和控件通知消息不同,因为因为WindowsWindows消息和控消息和控件通知消息就只能被件通知消息就只能被窗口和视图处理。窗口和视图处理。通过调用文档和视图的接口将修通过调用文档和视图的接口将修改的信息反馈
6、给文档类,实际的改的信息反馈给文档类,实际的数据更新仍然是由文档来完成的数据更新仍然是由文档来完成的在文档和用户之在文档和用户之间起中介作用间起中介作用视图可以直接或间接视图可以直接或间接的访问文档类中的成的访问文档类中的成员变量,它从文档类员变量,它从文档类中中(而不是从存储介质而不是从存储介质中中)将文档中的数据取将文档中的数据取出来,然后在屏幕上出来,然后在屏幕上显示文档的数据显示文档的数据它可以接收用户的输入它可以接收用户的输入,并接受用户的,并接受用户的修改修改6文档文档/视图结构的工作机制视图结构的工作机制视图通过视图通过GetDocumentGetDocument成员函数获得指向
7、相关成员函数获得指向相关联的文档对象的指针联的文档对象的指针通过该指针调用文通过该指针调用文档类的成员函数来档类的成员函数来从文档中读取数据从文档中读取数据视图把数据显示视图把数据显示于计算机屏幕上于计算机屏幕上用户通过与视图的用户通过与视图的交互来查看数据并交互来查看数据并对数据进行修改对数据进行修改视图通过相关联的文档类视图通过相关联的文档类的成员函数将经过修改的的成员函数将经过修改的数据传递给文档对象数据传递给文档对象文档对象获得修改过的数据之后,对文档对象获得修改过的数据之后,对其进行必要的修改,最后保存到永久其进行必要的修改,最后保存到永久介质介质(如磁盘文件如磁盘文件)中中7SDI
8、文档文档/视图应用程序示意图视图应用程序示意图 811.1.3 SDI程序中文档、视图对象的创建过程程序中文档、视图对象的创建过程 SDI程序中框架窗口、文档和视图的创建是在应用程序对象的程序中框架窗口、文档和视图的创建是在应用程序对象的InitInstance()成员函数中通过文档模板类完成的:成员函数中通过文档模板类完成的:CSingleDocTemplate*pDocTemplate;/创建单文档模板类对象创建单文档模板类对象pDocTemplate=new CSingleDocTemplate(IDR_MAINFRAME,RUNTIME_CLASS(CMyDoc),/CMyDoc是应用
9、程序中的文档类是应用程序中的文档类 RUNTIME_CLASS(CMainFrame),/CMainFrame是应用程序中的框架窗口是应用程序中的框架窗口 RUNTIME_CLASS(CMyView);/CMyView是应用程序中的视图类是应用程序中的视图类AddDocTemplate(pDocTemplate);/加载文档模板类对象到文档模板列表加载文档模板类对象到文档模板列表CCommandLineInfo cmdInfo;ParseCommandLine(cmdInfo);/初始化初始化CCommandLineInfo对象对象if(!ProcessShellCommand(cmdInfo
10、)/据对象中的信息启动程序据对象中的信息启动程序 return FALSE;m_pMainWnd-ShowWindow(SW_SHOW);m_pMainWnd-UpdateWindow();/显示和更新窗口显示和更新窗口911.1.4 SDI程序的消息传递过程程序的消息传递过程 当用户选择了菜单项,当用户选择了菜单项,单击了快捷键或工具条单击了快捷键或工具条按钮,系统就会发送按钮,系统就会发送WM_COMMAND消息。框消息。框架窗口实际上是大多数架窗口实际上是大多数WM_COMMAND消息的接消息的接受者,但受者,但WM_COMMAND消息还可以在视图、文消息还可以在视图、文档,甚至应用程序
11、类中档,甚至应用程序类中被处理。被处理。1011.2 Doc/View框架的主要成员框架的主要成员 Doc/View框架虽然可以调用成百上千个不框架虽然可以调用成百上千个不同的类,但是核心类只有五个同的类,但是核心类只有五个:CWinAppCDocumentCViewCDocTemplateCFrameWnd 1111.2.1 CWinApp 类类 CWinApp类代表主程序,类代表主程序,CWinApp本身是不可见的,本身是不可见的,它负责维护进程的启动、终止、消息循环、命令行参数、它负责维护进程的启动、终止、消息循环、命令行参数、资源管理资源管理 成员成员描述描述m_pszAppNamem
12、_pszAppName应用程序名应用程序名M_lpCmdLineM_lpCmdLine命令行参数命令行参数M_pMainWndM_pMainWnd应用程序主窗口指针应用程序主窗口指针M_pszExeNameM_pszExeName可执行文件名可执行文件名M_pszProfileNameM_pszProfileName配置配置INIINI文件名文件名M_pszRegistrKeyM_pszRegistrKey配置注册表主键值配置注册表主键值LoadCursorLoadCursor加载光标资源加载光标资源LoadIconLoadIcon加载图标资源加载图标资源部分部分主要主要成员成员1211.2.
13、2 CDocument类类 CDocument 的一般方法 方法方法 说明说明 GetTitle(GetTitle()获得文档标题获得文档标题 SetTitle(SetTitle()设置文档标题设置文档标题 GetPathName()GetPathName()获得文档数据文件的路径字符串获得文档数据文件的路径字符串 SetPathName()SetPathName()设置文档数据文件的路径字符串设置文档数据文件的路径字符串 GetDocTemplate()GetDocTemplate()获得指向描述文档类型的文档模板的指针获得指向描述文档类型的文档模板的指针 AddView()AddView(
14、)对与文档相关联的视图列表添加指定的视图对与文档相关联的视图列表添加指定的视图 RemoveView()RemoveView()从文档视图列表中删除视图从文档视图列表中删除视图 UpdateAllViews()UpdateAllViews()通知所有视图,文档己被通知所有视图,文档己被修改,应重画修改,应重画 DisconnectViews()DisconnectViews()使文档与视图相分离使文档与视图相分离 GetFile()GetFile()获得指向获得指向 CFileCFile 类型的指针类型的指针 13CDocument 的的虚虚拟拟方方法法方方法法说说明明O On nN Ne e
15、w wD Do oc cu um me en nt t()由由 M MF FC C 调调用用来来建建立立文文档档O On nO Op pe en nD Do oc cu um me en nt t()由由 M MF FC C 调调用用来来打打开开文文档档O On nS Sa av ve eD Do oc cu um me en nt t()由由 M MF FC C 调调用用来来保保存存文文档档O On nC Cl lo os se eD Do oc cu um me en nt t()由由 M MF FC C 调调用用来来关关闭闭文文档档C Ca an nC Cl lo os se eF Fr
16、 ra am me e()确确定定观观察察文文档档的的框框架架窗窗口口是是否否被被允允许许关关闭闭D De el le et te eC Co on nt te en nt ts s()在在未未撤撤消消文文档档对对象象时时删删除除文文档档数数据据R Re el le ea as se eF Fi il le e()释释放放文文件件以以允允许许其其它它应应用用程程序序使使用用S Sa av ve eM Mo od di if fi ie ed d()查查询询文文档档的的修修改改状状态态并并存存储储修修改改的的文文档档I Is sM Mo od di if fi ie ed d()确确定定文文档档
17、从从它它最最后后一一次次存存储储后后是是否否被被修修订订过过S Se et tM Mo od di if fi ie ed dF Fl la ag g()设设置置文文档档从从它它最最后后一一次次存存储储后后是是否否被被修修订订过过的的布布尔尔值值G Ge et tF Fi ir rs st tV Vi ie ew wP Po os si it ti io on n()获获得得视视图图列列表表头头的的位位置置G Ge et tN Ne ex xt tV Vi ie ew w()获获得得视视图图列列表表的的下下一一个个视视图图最常用的是最常用的是SetModifiedFlag()和和UpdateA
18、llViews()。文档内容被修改。文档内容被修改后,一般要调用后,一般要调用SetModifiedFlag()来设定一个标志。来设定一个标志。UpdateAllView()刷新所有和文档关联的视图。实际上该函数调用各个视图类的刷新所有和文档关联的视图。实际上该函数调用各个视图类的OnUpdate()函数。这样做可以保证各个视图之间的同步。函数。这样做可以保证各个视图之间的同步。14 用户可通过函数用户可通过函数GetFirstViewPosition()和和GetNextView()得到和文得到和文档关联的视图的指针,代码如下:档关联的视图的指针,代码如下:POSITION pos=GetF
19、irstViewPosition();/得到视图列表头的位置得到视图列表头的位置While(pos!=NULL)CView*pView=GetNextView(pos);/获得视图列表中的视图指针获得视图列表中的视图指针CDocument类在现在流行的类在现在流行的MVC(Modal、View、Control)设计模)设计模式中相当于其中的式中相当于其中的Modal,表示抽象数据模型。,表示抽象数据模型。文档最主要的功能如下:文档最主要的功能如下:l 打开保存文档打开保存文档l 维护文档相关的视图列表维护文档相关的视图列表l 维护文档修改标志维护文档修改标志l 通过电子邮件发送文档通过电子邮件
20、发送文档 用户修改文档数据时,调用用户修改文档数据时,调用SetModifiedFlag方法来标志数据被更方法来标志数据被更改过。当程序关闭该文档关联的最后一个视图的时候,文档会自改过。当程序关闭该文档关联的最后一个视图的时候,文档会自动提示你保存修改。动提示你保存修改。15从从CDocument类派生新的文档类的一般过程如下:类派生新的文档类的一般过程如下:为每一个文档类型从为每一个文档类型从CDocument类派生一个相应的文档类。类派生一个相应的文档类。为文档类添加成员变量,这些变量主要用来保存文档的数据,为文档类添加成员变量,这些变量主要用来保存文档的数据,并使其它的对象并使其它的对象
21、(如视图对象如视图对象)可以访问这些成员变量,从而实可以访问这些成员变量,从而实现文档和视图的相互搭配使用。现文档和视图的相互搭配使用。重载重载Serialize成员函数,实现文档数据的串行化。成员函数,实现文档数据的串行化。无论是保存文档或是打开文档,应用程序都是通过无论是保存文档或是打开文档,应用程序都是通过调用文档类的调用文档类的Serialize串行化成员函数来完成操作的。串行化成员函数来完成操作的。因此,在大多数情况下,我们都需要重载因此,在大多数情况下,我们都需要重载Serialize成员成员函数。函数。Serialize成员函数带有一个成员函数带有一个CArchive类型的参数,
22、类型的参数,这是一个与所打开的文件相关联的对象。一般情况下,这是一个与所打开的文件相关联的对象。一般情况下,总是使用总是使用CArchive对象来保存和打开文档。对象来保存和打开文档。16 CArchive对象是单向的,只用于保存或对象是单向的,只用于保存或读取两者之一,不能通过同一个读取两者之一,不能通过同一个CArchive对象既保存又读取文档。对象既保存又读取文档。在框架创建在框架创建CArchive对象时,已根据用对象时,已根据用户选择的是户选择的是“保存保存”(“另存为另存为”)还是还是“打开打开”来设置了来设置了CArchive对象的类型,对象的类型,我们可以使用我们可以使用CAr
23、chive类的成员函数类的成员函数IsStoring来检索当前来检索当前CArchive对象的类型,对象的类型,从而得知用户所期望的操作是保存还是从而得知用户所期望的操作是保存还是读取,执行不同的操作。读取,执行不同的操作。1711.2.3 CView类类 视图类视图类(CView)是从是从CWnd类下派生的类下派生的 视图类具有视图类具有CWnd的所有功的所有功能如:创建、移动、显示和能如:创建、移动、显示和隐藏窗口等。隐藏窗口等。CView类可以类可以接收任何接收任何Windows消息,而消息,而CDocument类则不行类则不行 IsSelected():确定文档是否被选中确定文档是否被
24、选中OnScroll():当用户滚动时,当用户滚动时,CView的响应的响应OnInitialUpdate():在类第一次构造后由在类第一次构造后由MFC调用调用OnDraw():由由MFC调用发出文档到设备描述表调用发出文档到设备描述表OnUpdate():由由MFC调用对文档的修改进行响应调用对文档的修改进行响应OnPrepareDC():在调用在调用OnDraw()前允许修改设备描述表由前允许修改设备描述表由MFC调用调用CView主要主要虚拟方法虚拟方法 18 CView类中最常用的是类中最常用的是OnDraw函数,该函数函数,该函数在屏幕发生变化或因为焦点的变化需要重绘在屏幕发生变化
25、或因为焦点的变化需要重绘时调用,没有该函数,就不可能在程序的切时调用,没有该函数,就不可能在程序的切换后保证屏幕的正确显示。换后保证屏幕的正确显示。注意注意:尽量不要在尽量不要在OnDraw之外的函数调用绘之外的函数调用绘图方法,那些方法不会在视图需要重新绘制图方法,那些方法不会在视图需要重新绘制的时候被自动调用。的时候被自动调用。若想在数据更新的时强制视图更新,可调用若想在数据更新的时强制视图更新,可调用Invalidate方法和方法和UpdateWindow方法来实现。方法来实现。19CEditView:简单的文本编辑器,类似:简单的文本编辑器,类似NotepadCListView:基于列
26、表的视图,类似文件夹浏览:基于列表的视图,类似文件夹浏览CTreeView:基于树状控件的视图,类似文件浏览左侧的树状结构:基于树状控件的视图,类似文件浏览左侧的树状结构CRichEditView:支持多种字体、:支持多种字体、OLE和和RTF格式的高级编辑器格式的高级编辑器CScrollView:支持滚动条的视图:支持滚动条的视图CFormView:窗体视图,支持在上边使用对话框控件:窗体视图,支持在上边使用对话框控件CRecordView:连接到:连接到ODBC数据库的视图数据库的视图CDaoRecordView:连接到:连接到DAO数据库的视图数据库的视图CView的子类的子类2011.
27、2.4 CDocTemplate类类 文档模板类在应用程序中有着非常重要的文档模板类在应用程序中有着非常重要的作用,是它将原本独立的文档、视图和框作用,是它将原本独立的文档、视图和框架窗口对象联系在一起架窗口对象联系在一起 文档模板类负文档模板类负责具体的关联责具体的关联文档、视图、文档、视图、框架的创建框架的创建 21 在在VC+中,文档对象、与文档对象相关联的视图对象中,文档对象、与文档对象相关联的视图对象以及为视图对象提供显示的框架窗口都是由文档模板创以及为视图对象提供显示的框架窗口都是由文档模板创建的。建的。每一种文档类型都有一种文档模板与之相对应,文档模每一种文档类型都有一种文档模板
28、与之相对应,文档模板负责创建和管理该文档类型的所有文档。板负责创建和管理该文档类型的所有文档。文档模板的构造函数的原型如下:文档模板的构造函数的原型如下:CDocTemplate(UINT nIDResource,/与文档一同使用的各种资源的资源标识符与文档一同使用的各种资源的资源标识符CRuntimeClass*pDocClass,/指向文档派生文档类的对象的指针指向文档派生文档类的对象的指针CRuntimeClass*pFrameClass,/框架类的派生框架类的对象指针框架类的派生框架类的对象指针CRuntimeClass*pViewClass/指向指向CView的派生视图类的对象指针的
29、派生视图类的对象指针 )在在SDISDI应用程序中只有一个文档模板对象,应用程序中只有一个文档模板对象,而而MDIMDI应用程序需要针对不同类型的文档定应用程序需要针对不同类型的文档定义不同的文档模板对象。义不同的文档模板对象。22当前位置当前位置被访问的位置被访问的位置访问方法访问方法文档文档视图视图GetFirstViewPositionGetNextView文档文档模板模板GetDocTemplate视图视图文档文档GetDocument视图视图框架框架GetParentFrame框架框架视图视图GetActiveView框架框架文档文档GetActiveDocumentMDI主框架主框
30、架 MDI子框架子框架MDIGetActiveMDI子框架子框架 MDI主框架主框架GetParentFrame任何位置任何位置应用程序应用程序AfxGetApp任何位置任何位置主框架主框架AfxGetMainWndDoc/View结构的五个基本成员经结构的五个基本成员经常需要互相访问,假设某个视图常需要互相访问,假设某个视图想要获得文档,或某个框架需要想要获得文档,或某个框架需要获得活动视图,可以通过此表提获得活动视图,可以通过此表提供的方法进行解决供的方法进行解决 2311.2.5 CFrameWnd类类 CFrameWnd类在类在Doc/View结构中起着结构中起着举足轻重的作用。举足轻
31、重的作用。框架窗口维护了很多幕后的工作,框架窗口维护了很多幕后的工作,例如工具条、菜单、状态条的显示、更例如工具条、菜单、状态条的显示、更新,视图的位置和显示,其它可停靠空新,视图的位置和显示,其它可停靠空间的停靠和动态尺寸调整。许多默认为间的停靠和动态尺寸调整。许多默认为MFC应用程序应该具备的基本功能都是应用程序应该具备的基本功能都是CframeWnd类在完成类在完成 2411.3文档操作中的一些重要概念文档操作中的一些重要概念 串行化处理串行化处理文档文档操作操作文档的消息映射文档的消息映射文档消息传递文档消息传递文件打开文件打开文件保存文件保存2511.3.1 串行化处理串行化处理 串
32、行化:串行化:将对象写入字节流和从字节流恢复对将对象写入字节流和从字节流恢复对象的操作象的操作 串行化除了可以使用文件保存对象之外,串行化除了可以使用文件保存对象之外,还可以通过网络、串口传输对象,还可以通过网络、串口传输对象,因此使因此使用字节流用字节流。串行化代码如下:。串行化代码如下:void CMDIDoc:Serialize(CArchive&ar)if(ar.IsStoring()/TODO:add storing code here else/TODO:add loading code here 26 使用串行化的好处是不需要重载文件打使用串行化的好处是不需要重载文件打开、文件保
33、存之类的方法,开、文件保存之类的方法,MFC框架会自动完框架会自动完成这些任务,并自动调用文档类的成这些任务,并自动调用文档类的Serialize方方法来完成串行化过程。法来完成串行化过程。如果文档的抽象数据只有一个字符串,如果文档的抽象数据只有一个字符串,那么你只需要在那么你只需要在Serialize中添加相应语句就可中添加相应语句就可以完成串行化过程。以完成串行化过程。如果不使用如果不使用MFC提供的串行化框架,那么提供的串行化框架,那么就需要重载一些函数,来获取文件名,然后就需要重载一些函数,来获取文件名,然后自己来读写文件完成对象的串行化。自己来读写文件完成对象的串行化。27在进行串行
34、化处在进行串行化处理时,通常是通理时,通常是通过过CArchive(档案档案)类来完成的类来完成的成员成员描述描述WriteString写入字符串写入字符串ReadString读取字符串读取字符串ReadClass读取类信息读取类信息WriteClass写入类信息写入类信息Close关闭档案关闭档案GetObjectSchema读取对象版本号读取对象版本号SetObjectSchema设置对象版本号设置对象版本号M_pDocument使用该档案的文档使用该档案的文档Read读取字节内容读取字节内容Write写入字节内容写入字节内容GetFile获取底层的获取底层的CFile对象对象operat
35、or从流中读取基本类型从流中读取基本类型IsStoring是否处于保存状态是否处于保存状态Flush将缓冲中的数据强制写入流中将缓冲中的数据强制写入流中Abort在不发送异常的情况下关闭档案在不发送异常的情况下关闭档案ReadObject读取串行化对象读取串行化对象WriteObject写入串行化对象写入串行化对象CArchive类的类的常用成员常用成员 28若使用串行化,可以不关心若使用串行化,可以不关心文件打开关闭的具体过程,文件打开关闭的具体过程,只需要完善只需要完善Serialize方法即方法即可,但是很多应用程序都希可,但是很多应用程序都希望来亲自控制用户打开保存望来亲自控制用户打开
36、保存文件的过程文件的过程 缺省处理方法缺省处理方法CWinApp:OnFileOpenCWinApp:OpenDocumentFileCDocTemplate:OpenDocumentFileCDocument:OnOpenDocumentCDocument:SerializeCDocument:OnFileSave/OnFileSaveAsCDocument:OnSaveDocument文件打开或保存文件打开或保存时重载的某一个时重载的某一个缺省处理方法缺省处理方法2911.3.2 消息映射消息映射 使用使用ClassWizard来添加消息映射,但来添加消息映射,但有时,有时,ClassWi
37、zard不支持某些类的消息不支持某些类的消息映射,需自己添加一些自定义的消息,映射,需自己添加一些自定义的消息,这时都需要手工添加消息映射代码这时都需要手工添加消息映射代码 数组中数组中存储的存储的信息信息消息应用于的控件消息应用于的控件ID,或者,或者ID范围范围所处理的消息所处理的消息消息所传递的参数消息所传递的参数消息所期望的返回值消息所期望的返回值 消息映射本质上就消息映射本质上就是一个数组,是一个数组,MFC使用该数组来确定使用该数组来确定消息传递时具体要消息传递时具体要传递给哪一个函数传递给哪一个函数30 当当MFC收到消息后,便自动确定目标窗口收到消息后,便自动确定目标窗口和相应
38、的和相应的MFC类的实例。然后它便搜索窗口的类的实例。然后它便搜索窗口的消息映射寻找匹配的项。若窗口中没有处理该消息映射寻找匹配的项。若窗口中没有处理该消息的处理程序,消息的处理程序,MFC便进一步搜索窗口的父便进一步搜索窗口的父类。如果父类也没有找到处理该消息的函数,类。如果父类也没有找到处理该消息的函数,MFC便将消息传递给该窗口的原窗口过程便将消息传递给该窗口的原窗口过程 31 在消息映射的时候,仅仅靠在消息映射的时候,仅仅靠ClassWizard生成的宏是不够生成的宏是不够的,有时需要向已有的消息映射添加自己的宏,但所添加的的,有时需要向已有的消息映射添加自己的宏,但所添加的宏一定要放
39、在宏一定要放在ClassWizard的特殊注释之外。的特殊注释之外。以下是由以下是由AppWizard产生的默认产生的默认MDI视图的消息映射,另外添视图的消息映射,另外添加了一个菜单项的处理和一个加了一个菜单项的处理和一个WM_ERASEBKGND消息的映射:消息的映射:BEGIN_MESSAGE_MAP(CMDIView,CView)/AFX_MSG_MAP(CMDIView)ON_COMMAND(ID_OPER_TEST,OnOperTest)ON_UPDATE_COMMAND_UI(ID_OPER_TEST,OnUpdateOperTest)ON_WM_ERASEBKGND()/AFX
40、_MSG_MAP /Standard printing commands ON_COMMAND(ID_FILE_PRINT,CView:OnFilePrint)ON_COMMAND(ID_FILE_PRINT_DIRECT,CView:OnFilePrint)ON_COMMAND(ID_FILE_PRINT_PREVIEW,CView:OnFilePrintPreview)END_MESSAGE_MAP()位于位于AFX_MSG_MAP之间的宏来自之间的宏来自ClassWizard特定宏特定宏 ON_COMMAND是通用宏是通用宏32在第二个在第二个AFX_MSG_MAP之后,可以添加自己的之
41、后,可以添加自己的消息映射,消息映射,ClassWizard不检查这里,这里的消不检查这里,这里的消息映射不会出现在息映射不会出现在ClassWizard中的中的 3311.3.3 消息传递消息传递 由于用户可以在很多由于用户可以在很多MFC类中映射同一个类中映射同一个消息,如可以在文档和视图中同时映射消息,如可以在文档和视图中同时映射打开文件的消息,这样就需要消息有明打开文件的消息,这样就需要消息有明确的来源,也有明确的接收者,因此需确的来源,也有明确的接收者,因此需要判断消息传递的顺序。要判断消息传递的顺序。当前视图当前视图当前文档当前文档与当前视图与当前视图/文档关文档关联的文档模板联的
42、文档模板子框架窗口(只有子框架窗口(只有MDIMDI有该有该步骤)步骤)主框架窗口主框架窗口应用程序对象应用程序对象3411.4 SDI编程实例编程实例【例【例11-1】在主窗】在主窗口中央显示一文口中央显示一文本本“您好您好,单文档单文档界面的例程界面的例程!”。单。单击击“改变显示文改变显示文本本”菜单项,可菜单项,可弹出一个对话框,弹出一个对话框,通过此对话框可通过此对话框可改变主窗口中的改变主窗口中的显示文本内容显示文本内容 35(1)创建工程文件和对话框资源创建工程文件和对话框资源 创建一个单创建一个单文档工程文件文档工程文件MySdi,然后添,然后添加对话框资源加对话框资源(2)为
43、为CMySdiDoc类添加成员变量类添加成员变量 在在CMySdiDoc类的定义中增加如下的代码:类的定义中增加如下的代码:CString m_str;用以存放用以存放字符串字符串36(3)文档变量初始化文档变量初始化打开打开CMySdiDoc.cpp文件,在文件,在 OnNewDocument成员函数加入以下代码:成员函数加入以下代码:BOOL CMySdiDoc:OnNewDocument()if(!CDocument:OnNewDocument()return FALSE;m_str=“您好,单文档界面的例程!您好,单文档界面的例程!”/初始化成员变初始化成员变量量return TRUE
44、;37(4)视图的输出视图的输出 MySdi程序视图类程序视图类CMySdiView类的类的OnDraw成员函数:成员函数:void CMySdiView:OnDraw(CDC*pDC)CMySdiDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);CRect rectClient;GetClientRect(rectClient);/获取当前客户区的指针获取当前客户区的指针 CSize sizeClient=rectClient.Size();/获取当前客户区的大小获取当前客户区的大小 CString str=pDoc-m_str;/从文件中读取数据从文件中读
45、取数据 CSize sizeTextExtent=pDC-GetTextExtent(str);/用新选定的字体绘制字符串用新选定的字体绘制字符串 pDC-TextOut(sizeClient.cx-sizeTextExtent.cx)/2,(sizeClient.cy-sizeTextExtent.cy)/2,str);调用调用GetDocument()得到文档类的指针,得到文档类的指针,将文档对象成将文档对象成员变量复制到字符串员变量复制到字符串str中中,调用,调用TextOut()将将m_str的内的内容显示到框架窗口中的视图中。容显示到框架窗口中的视图中。38(5)文档串行化文档串行
46、化 在在“编辑编辑”菜单中添加菜单项菜单中添加菜单项“改变显示文改变显示文本本”(ID_EDIT_CHANGETEXT)。单击此。单击此菜单项可以将将对视图中显示文本所做的修改菜单项可以将将对视图中显示文本所做的修改保存到一个磁盘文件中,具体的实现方法如下:保存到一个磁盘文件中,具体的实现方法如下:void CMySdiDoc:OnEditChangetext()CDlgInput inputDlg;/创建一个创建一个 CInputDlg类的对象类的对象inputDlg if(inputDlg.DoModal()=IDOK)/显示对话框显示对话框 m_str=inputDlg.m_input;
47、/获取输入的字符串获取输入的字符串UpdateAllViews(NULL);/更新视图更新视图 39为了在为了在CMySdiDoc类中定义对话框类类中定义对话框类CDlgInput对象,对象,还必须在还必须在MySdiDoc.cpp文件中加入文件中加入CDlgInput类的头类的头文件文件DlgInput.h,代码如下:,代码如下:#include DlgInput.h/加入头文件加入头文件 为了把这些修改保存到磁盘文件中,并在需要时为了把这些修改保存到磁盘文件中,并在需要时可以打开所保存的磁盘文件读取文档,需要重载可以打开所保存的磁盘文件读取文档,需要重载CExampleDoc类的类的Ser
48、ialize函数来完成串行化。重载函数来完成串行化。重载后的后的Serialize函数的代码如下:函数的代码如下:void CMySdiDoc:Serialize(CArchive&ar)if(ar.IsStoring()arm_str;/读取文档内容读取文档内容 4011.5 MDI编程实例编程实例【例【例16-216-2】创建多文档的应用程序,可以打开两种类】创建多文档的应用程序,可以打开两种类型的文档。型的文档。MyMdi1MyMdi1是系统默认生成的文档是系统默认生成的文档(可以打印可以打印)。MyMdi21MyMdi21是另一个用户添加的文档类型是另一个用户添加的文档类型(不允许打印
49、不允许打印),在程序的窗口中显示在程序的窗口中显示“您好您好,多文档界面的例程多文档界面的例程!”!”,注意如果活动文档的注意如果活动文档的 类型改变,则菜单的类型改变,则菜单的 “编辑编辑”项的子菜单项的子菜单不不 同,工具条上的同,工具条上的“打打印印”按钮的激活状态也不按钮的激活状态也不 同同41(1)创建创建MDI工程文件工程文件 创建创建MyMdi工程文件,工程文件,在在Step 4 of 6 的窗口中,的窗口中,单击单击Advanced按钮,在按钮,在File extention对话框中加对话框中加入入mmd,完成后的应用,完成后的应用程序的文件将使用程序的文件将使用“.mmd”为
50、扩展名,文为扩展名,文件过滤器域显示为件过滤器域显示为“MyMdi文件文件(*.mmb)”,在在Step 6 of 6 的对话框中,的对话框中,为为CMyMdiView类设置基类设置基类为类为CEditView。42(2)创建第二种文档和视图类创建第二种文档和视图类View ClassWizard Class Info Add Class New 43(3)创建资源创建资源 在在Resource.h文件中,手工加入下列代码文件中,手工加入下列代码:#define IDR_MYMDITYPE2 135 这样就定义了第二类文档的文档、视图和框架窗这样就定义了第二类文档的文档、视图和框架窗口共同的资