1
第 11章 单文档与多文档
本章主要介绍 Visual C++中的
文档 /视图结构的工作机制
2
11.1 概述
3
11.1.1单文档界面与多文档界面
VC的 MFC库支
持三种不同
的应用程序
单文档界面 (SDI)
多文档界面 (MDI)
基于对话框的应用程序
SDI的应用程序
只有一个窗口
MDI的应用程序每次
可以读写多个文件或
文档,可同时对多个
文档进行操作,可以
有多个子窗口




在创建 SDI界面的应用程序时,不生成
CChildFrame类,CMainFrame类的基类
为 CFrameWnd
在创建 MDI界面的应用程序时,
CMainFrame类的基类为
CMDIFrameWnd
使用 AppWizard创建
SDI和 MDI界面的应
用程序的过程几乎完
全一样
4
由于每一个文档可以有多个视图,但
每个视图只能对应于一个确定的文档
多文档程序需要解决的问题仅仅是多
个文档的数据管理方法的问题
多文档程序,最初的文档模板只支持主窗口,但每次打开一
个新文档时都调用 CDocument的函数 OnNewDocument,建
立一个由 CMDIChildWnd派生的新的 MDI子窗口,这些窗口
中保存着各种已打开的文档,所有的细节都由 MFC库处理
视图是文档的不同表现形式,一个 *.html
语言的文件,在浏览器里和在记事本中打
开的表现形式是不同的但它们操作的是同
一个文件这就是一个文档对应两视图
5
11.1.2 文档 /视图结构
在 文档 /视图 结构中
对数据进行管理和维
护,数据保存在文档
类的成员变量中
文档类 通过串行化
的过程将数据保存
到磁盘文件或数据库中
文档类 还可处理来自如
菜单、工具栏按钮和加
速键的 WM_COMMAND消息
除 WM_COMMAND外,文档 不
能 处理其它的 Windows消息
由此我们可
以看出,命
令消息可以
被多种对象
处理,这些
对象除了窗
口和视图外
,还可以是
文档、文档
模板或应用
程序本身
这一点与 Windows消息
和控件通知消息不同,
因为 Windows消息和控
件通知消息就只能被
窗口和视图处理。
通过调用文档和视图的接口将修
改的信息反馈给文档类,实际的
数据更新仍然是由文档来完成的
在文档和用户之
间起中介作用
视图可以直接或间接
的访问文档类中的成
员变量,它从文档类
中 (而不是从存储介质
中 )将文档中的数据取
出来,然后在屏幕上
显示文档的数据
它可以接收用户的输入
,并接受用户的 修改
6
文档 /视图结构的工作机制
视图通过 GetDocument
成员函数获得指向相关
联的文档对象的指针
通过该指针调用文
档类的成员函数来
从文档中读取数据 视图把数据显示
于计算机屏幕上
用户通过与视图的
交互来查看数据并
对数据进行修改视图通过相关联的文档类的成员函数将经过修改的
数据传递给文档对象
文档对象获得修改过的数据之后,对
其进行必要的修改,最后保存到永久
介质 (如磁盘文件 )中
7
SDI文档 /视图应用程序示意图
8
11.1.3 SDI程序中文档、视图对象的创建过程
SDI程序中框架窗口、文档和视图的创建是在应用程序对象的
InitInstance()成员函数中通过文档模板类完成的:
CSingleDocTemplate * pDocTemplate; //创建单文档模板类对象
pDocTemplate = new CSingleDocTemplate
(IDR_MAINFRAME,
RUNTIME_CLASS (CMyDoc),//CMyDoc是应用程序中的文档类
RUNTIME_CLASS (CMainFrame),//CMainFrame是应用程序中的框架窗口
RUNTIME_CLASS (CMyView) ); //CMyView是应用程序中的视图类
AddDocTemplate(pDocTemplate); //加载文档模板类对象到文档模板列表

CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo); //初始化 CCommandLineInfo对象
if(! ProcessShellCommand(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框架虽然可以调用成百上千个不
同的类,但是核心类只有五个,
CWinApp
CDocument
CView
CDocTemplate
CFrameWnd
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 CDocument类
C D ocu m ent 的一般方法
方法 说明
GetTitle( ) 获得文档标题
SetTitle( ) 设置文档标题
GetPathName() 获得文档数据文件的路径字符串
SetPathName() 设置文档数据文件的路径字符串
GetDocTemplate() 获得指向描述文档类型的文档模板的指针
AddView() 对与文档相关联的视图列表添加指定的视图
RemoveView() 从文档视图列表中删除视图
UpdateAllViews() 通知所有视图,文档己被 修改,应重画
DisconnectViews() 使文档与视图相分离
GetFile() 获得指向 CFile 类型的指针
13
C D ocum ent 的虚拟方法
方法 说明
O n Ne w D o c u me n t ( ) 由 MFC 调用来 建立 文档
O n Op e n D o c um e n t ( ) 由 MFC 调用来 打开 文档
O n Sa v e D o c um e n t ( ) 由 MFC 调用来 保存 文档
O n Cl o s e D o cu m e n t ( ) 由 MFC 调用来 关闭 文档
C a nC l o s e F ra m e ( ) 确定观察文档的框架窗口是否被允许关闭
D e le t e C o n te n t s ( ) 在未撤消文档对象时删除文档数据
R e le a s e F i le ( ) 释放文件以允许其它应用程序使用
S a ve M o d i f ie d ( ) 查询文档的修改状态并存储修改的文档
I s Mo d i f i e d () 确定文档从它最后一次存储后是否被修订过
S e tM o d i f i ed F l a g () 设置文档从它最后一次存储后是否被修订过的布尔值
G e tF i r s t V ie w P o s i ti o n ( ) 获得视图列表头的位置
G e tN e x t V i ew ( ) 获得视图列表的下一个视图
最常用的是 SetModifiedFlag()和 UpdateAllViews()。文档内容被修改
后,一般要调用 SetModifiedFlag()来设定一个标志。 UpdateAllView()
刷新所有和文档关联的视图。实际上该函数调用各个视图类的
OnUpdate()函数。这样做可以保证各个视图之间的同步。
14
用户可通过函数 GetFirstViewPosition()和 GetNextView()得到和文
档关联的视图的指针,代码如下:
POSITION pos = GetFirstViewPosition(); //得到视图列表头的位置
While(pos != NULL)
{ CView *pView = GetNextView(pos); //获得视图列表中的视图指针

}
CDocument类在现在流行的 MVC( Modal,View,Control)设计模
式中相当于其中的 Modal,表示抽象数据模型。
文档最主要的功能如下:
l 打开保存文档
l 维护文档相关的视图列表
l 维护文档修改标志
l 通过电子邮件发送文档
用户修改文档数据时,调用 SetModifiedFlag方法来标志数据被更
改过。当程序关闭该文档关联的最后一个视图的时候,文档会自
动提示你保存修改。
15
从 CDocument类派生新的文档类的一般过程如下:
?为每一个文档类型从 CDocument类派生一个相应的文档类。
?为文档类添加成员变量,这些变量主要用来保存文档的数据,
并使其它的对象 (如视图对象 )可以访问这些成员变量,从而实
现文档和视图的相互搭配使用。
?重载 Serialize成员函数,实现文档数据的串行化。
无论是保存文档或是打开文档,应用程序都是通过
调用文档类的 Serialize串行化成员函数来完成操作的。
因此,在大多数情况下,我们都需要重载 Serialize成员
函数。 Serialize成员函数带有一个 CArchive类型的参数,
这是一个与所打开的文件相关联的对象。一般情况下,
总是使用 CArchive对象来保存和打开文档。
16
CArchive对象是单向的,只用于保存或
读取两者之一,不能通过同一个 CArchive
对象既保存又读取文档。
在框架创建 CArchive对象时,已根据用
户选择的是,保存” (,另存为” )还是
“打开” 来设置了 CArchive对象的类型,
我们可以使用 CArchive类的成员函数
IsStoring来检索当前 CArchive对象的类型,
从而得知用户所期望的操作是保存还是
读取,执行不同的操作。
17
11.2.3 CView类
视图类 (CView)是从 CWnd类下派生的
视图类具有 CWnd的所有功
能如:创建、移动、显示和
隐藏窗口等。 CView类可以
接收任何 Windows消息,而
CDocument类则不行
IsSelected():确定文档是否被选中
OnScroll():当用户滚动时,CView的响应
OnInitialUpdate():在类第一次构造后由 MFC调用
OnDraw():由 MFC调用发出文档到设备描述表
OnUpdate():由 MFC调用对文档的修改进行响应
OnPrepareDC():在调用 OnDraw()前允许修改设备描述表由 MFC调用
CView主要
虚拟方法
18
CView类中最常用的是 OnDraw函数,该函数
在屏幕发生变化或因为焦点的变化需要重绘
时调用,没有该函数,就不可能在程序的切
换后保证屏幕的正确显示。
注意, 尽量不要在 OnDraw之外的函数调用绘
图方法,那些方法不会在视图需要重新绘制
的时候被自动调用。
若想在数据更新的时强制视图更新,可调用
Invalidate方法和 UpdateWindow方法来实现。
19
CEditView:简单的文本编辑器,类似 Notepad
CListView:基于列表的视图,类似文件夹浏览
CTreeView:基于树状控件的视图,类似文件浏览左侧的树状结构
CRichEditView:支持多种字体,OLE和 RTF格式的高级编辑器
CScrollView:支持滚动条的视图
CFormView:窗体视图,支持在上边使用对话框控件
CRecordView:连接到 ODBC数据库的视图
CDaoRecordView:连接到 DAO数据库的视图
CView的子类
20
11.2.4 CDocTemplate类
文档模板类在应用程序中有着非常重要的
作用,是它将原本独立的文档、视图和框
架窗口对象联系在一起
文档模板类负
责具体的关联
文档、视图、
框架的创建
21
在 VC++中,文档对象、与文档对象相关联的视图对象
以及为视图对象提供显示的框架窗口都是由文档模板创
建的。
每一种文档类型都有一种文档模板与之相对应,文档模
板负责创建和管理该文档类型的所有文档。
文档模板的构造函数的原型如下:
CDocTemplate
(UINT nIDResource,//与文档一同使用的各种资源的资源标识符
CRuntimeClass* pDocClass,// 指向文档派生文档类的对象的指针
CRuntimeClass* pFrameClass,//框架类的派生框架类的对象指针
CRuntimeClass* pViewClass //指向 CView的派生视图类的对象指针
) 在 SDI应用程序中只有一个文档模板对象,
而 MDI应用程序需要针对不同类型的文档定
义不同的文档模板对象。
22
当前位置 被访问的位置 访问方法
文档 视图 GetFirstViewPosition
GetNextView
文档 模板 GetDocTemplate
视图 文档 GetDocument
视图 框架 GetParentFrame
框架 视图 GetActiveView
框架 文档 GetActiveDocument
MDI主框架 MDI子框架 MDIGetActive
MDI子框架 MDI主框架 GetParentFrame
任何位置 应用程序 AfxGetApp
任何位置 主框架 AfxGetMainWnd
Doc/View结构的五个基本成员经
常需要互相访问,假设某个视图
想要获得文档,或某个框架需要
获得活动视图,可以通过此表提
供的方法进行解决
23
11.2.5 CFrameWnd类
CFrameWnd类在 Doc/View结构中起着
举足轻重的作用。
框架窗口维护了很多幕后的工作,
例如工具条、菜单、状态条的显示、更
新,视图的位置和显示,其它可停靠空
间的停靠和动态尺寸调整。许多默认为
MFC应用程序应该具备的基本功能都是
CframeWnd类在完成
24
11.3文档操作中的一些重要概念
串行化处理
文档
操作
文档的消息映射
文档消息传递
文件打开
文件保存
25
11.3.1 串行化处理
串行化,将对象写入字节流和从字节流恢复对
象的操作
串行化除了可以使用文件保存对象之外,
还可以通过网络、串口传输对象,因此使
用字节流 。串行化代码如下:
void CMDIDoc::Serialize(CArchive& ar)
{ if (ar.IsStoring())
{ // TODO,add storing code here }
else
{ // TODO,add loading code here }
}
26
使用串行化的好处是不需要重载文件打
开、文件保存之类的方法,MFC框架会自动完
成这些任务,并自动调用文档类的 Serialize方
法来完成串行化过程。
如果文档的抽象数据只有一个字符串,
那么你只需要在 Serialize中添加相应语句就可
以完成串行化过程。
如果不使用 MFC提供的串行化框架,那么
就需要重载一些函数,来获取文件名,然后自
己来读写文件完成对象的串行化。
27
在进行串行化处
理时,通常是通
过 CArchive(档案 )
类来完成的
成员 描述
WriteString 写入字符串
ReadString 读取字符串
ReadClass 读取类信息
WriteClass 写入类信息
Close 关闭档案
GetObjectSchema 读取对象版本号
SetObjectSchema 设置对象版本号
M_pDocument 使用该档案的文档
Read 读取字节内容
Write 写入字节内容
GetFile 获取底层的 CFile对象
operator<< 将基本类型写入流中
IsLoading 是否处于读取状态
operator>> 从流中读取基本类型
IsStoring 是否处于保存状态
Flush 将缓冲中的数据强制写入流中
Abort 在不发送异常的情况下关闭档案
ReadObject 读取串行化对象
WriteObject 写入串行化对象
CArchive类的
常用成员
28
若使用串行化,可以不关心
文件打开关闭的具体过程,
只需要完善 Serialize方法即
可,但是很多应用程序都希
望来亲自控制用户打开保存
文件的过程
缺省处理方法
CWinApp::OnFileOpen
CWinApp::OpenDocumentFile
CDocTemplate::OpenDocumentFile
CDocument::OnOpenDocument
CDocument::Serialize
CDocument::OnFileSave/OnFileSaveAs
CDocument::OnSaveDocument
文件打开或保存
时重载的某一个
缺省处理方法
29
11.3.2 消息映射
使用 ClassWizard来添加消息映射,但
有时,ClassWizard不支持某些类的消息
映射,需自己添加一些自定义的消息,
这时都需要手工添加消息映射代码
数组中
存储的
信息
消息应用于的控件 ID,或者 ID范围
所处理的消息
消息所传递的参数
消息所期望的返回值
消息映射本质上就
是一个数组,MFC
使用该数组来确定
消息传递时具体要
传递给哪一个函数
30
当 MFC收到消息后,便自动确定目标窗口
和相应的 MFC类的实例。然后它便搜索窗口的
消息映射寻找匹配的项。若窗口中没有处理该
消息的处理程序,MFC便进一步搜索窗口的父
类。如果父类也没有找到处理该消息的函数,
MFC便将消息传递给该窗口的原窗口过程
31
在消息映射的时候,仅仅靠 ClassWizard生成的宏是不够
的,有时需要向已有的消息映射添加自己的宏,但所添加的
宏一定要放在 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_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
之后,可以添加自己的
消息映射,ClassWizard
不检查这里,这里的消
息映射不会出现在
ClassWizard中的
33
11.3.3 消息传递
由于用户可以在很多 MFC类中映射同一个
消息,如可以在文档和视图中同时映射
打开文件的消息,这样就需要消息有明
确的来源,也有明确的接收者,因此需
要判断消息传递的顺序。
当前视图 ?当前文档 ?与当前视图 /文档关
联的文档模板 ?子框架窗口(只有 MDI有该
步骤) ?主框架窗口 ?应用程序对象
34
11.4 SDI编程实例
【 例 11-1】 在主窗
口中央显示一文
本“您好,单文档
界面的例程 !”。单
击“改变显示文
本”菜单项,可
弹出一个对话框,
通过此对话框可
改变主窗口中的
显示文本内容
35
(1) 创建工程文件和对话框资源
创建一个单
文档工程文件
MySdi,然后添
加对话框资源
(2) 为 CMySdiDoc类添加成员变量
在 CMySdiDoc类的定义中增加如下的代码:
CString m_str;
用以存放
字符串
36
(3) 文档变量初始化
打开 CMySdiDoc.cpp文件,在 OnNewDocument
成员函数加入以下代码:
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); // 获取当前客户区的指针
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的内
容显示到框架窗口中的视图中。
38
(5) 文档串行化
在,编辑” 菜单中添加菜单项, 改变显示文
本, ( ID_EDIT_CHANGETEXT ) 。单击此
菜单项可以将将对视图中显示文本所做的修改
保存到一个磁盘文件中,具体的实现方法如下:
void CMySdiDoc::OnEditChangetext()
{ CDlgInput inputDlg; //创建一个
CInputDlg类的对象 inputDlg
if(inputDlg.DoModal()==IDOK) //显示对话框
{
m_str=inputDlg.m_input; //获取输入的字符串
UpdateAllViews(NULL); //更新视图
}
}
39
为了在 CMySdiDoc类中定义对话框类 CDlgInput对象,
还必须在 MySdiDoc.cpp文件中加入 CDlgInput类的头
文件 DlgInput.h,代码如下:
#include "DlgInput.h" //加入头文件
为了把这些修改保存到磁盘文件中,并在需要时
可以打开所保存的磁盘文件读取文档,需要重载
CExampleDoc类的 Serialize函数来完成串行化。重载
后的 Serialize函数的代码如下:
void CMySdiDoc::Serialize(CArchive& ar)
{ if (ar.IsStoring())
ar<<m_str; //保存文档内容
else
ar>>m_str; //读取文档内容
}
40
11.5 MDI编程实例
【 例 16-2】 创建多文档的应用程序,可以打开两种类
型的文档。 MyMdi1是系统默认生成的文档 (可以打印 )。
MyMdi21是另一个用户添加的文档类型 (不允许打印 ),
在程序的窗口中显示, 您好,多文档界面的例程 !”,
注意如果活动文档的
类型改变,则菜单的
,编辑, 项的子菜单

同,工具条上的, 打
印,
按钮的激活状态也不

41
(1) 创建 MDI工程文件
创建 MyMdi工程文件,
在 Step 4 of 6 的窗口中,
单击 Advanced按钮,在
File extention对话框中加
入 mmd,完成后的应用
程序的文件将使用
,.mmd”为扩展名,文
件过滤器域显示为
,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
这样就定义了第二类文档的文档、视图和框架窗口
共同的资源 ID,以后定义的菜单、文档模板等资源
均可以使用此 ID
文档模板字符串的格式如下:
nIDResource
<WindowTitle>\n
<DocName>\n
<FileNewName>\n
<FilterName>\n
<FilterExt>\n
<RegFileTypeID>\n
<RegFileTypeName>\n
<FilterMacName(FilterWinName)>
44
对于第一个文档,应用程序向导直接产生了一
个文档模板,现在必须手工加入第二个资源模
板字符串。具体的方法是:打开 MyMdi.rc文件,
首先找到如下代码:
IDR_MYMDITYPE
"\nMyMdi
\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 CMyMdiApp::InitInstance()
{ …
CMultiDocTemplate* pDocTemplate2;
pDocTemplate2 = new CMultiDocTemplate(
IDR_MYMDITYPE2,
RUNTIME_CLASS(CMyMdiDoc2),
// MDI派生文档类的 CRuntimeClass对象的指针
RUNTIME_CLASS(CChildFrame),
// MDI派生子框架类的 CRuntimeClass对象的指针
RUNTIME_CLASS(CMyMdiView2));// 创建文档模板对象
AddDocTemplate(pDocTemplate2);
//将新模板添加到应用程序的文档模板列表中

}
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
文档变量初始化:
为了能够在的二个文档中显示“您好,多文档界面的例
程 !”,需在 CMyMdiDoc2类的 OnNewDocument()成员
函数中为变量 m_str赋初值。因此需添加下列代码:
BOOL CMyMdiDoc2::OnNewDocument()
{ if (!CDocument::OnNewDocument())
return FALSE;
m_str="您好,多文档界面的例程 !";
return TRUE;
}
49
添加菜单处理函数:
在类 CMyMdiDoc2中为“编辑”菜单中的菜单项, 改变显示
文本” 添加消息处理函数 OnEditChangeText(),加入代码如下:
void CMyMdiDoc2::OnEditChangetext()
{// 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
// MyMdiDoc2.cpp, implementation of the CMyMdiDoc2 class
#include "DlgInput.h" //加入头文件
50
文档串行化,
为了把对视图中显示文本的修改保存到磁盘文件中,
并在需要时可以打开所保存的磁盘文件读取文档,必
须重载 CExampleDoc类的 Serialize函数来完成串行化
重载后的 Serialize()函数的代码如下:
// CMyMdiDoc2 serialization
void CMyMdiDoc2::Serialize(CArchive& ar)
{
if (ar.IsStoring())
ar<<m_str; //保存文档内容
else
ar>>m_str; //读取文档内容
}
51
(c) 视图的输出
为将 m_str的内容显示到视图的框架窗口中。需要在 OnDraw()函
数中加入下列代码,注意下列代码的头两行与系统自动生成的代
码的差异,需要按下列方式进行调整。
void CMyMdiView2::OnDraw(CDC* pDC)
{ CMyMdiDoc2* pDoc = (CMyMdiDoc2*)GetDocument();
//得到文档对象指针
ASSERT_VALID(pDoc);
// TODO,add draw code for native data here
CRect 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"