摘要:文档视图结构及其相互作用,文档视图中的切分窗口及一档多视。
关键词:文档 视图 切分窗口 一档多视
MFC应用程序的大部分代码都会被添加在文档和视图这两个类中,它们紧密相连,是用户与文档之间的交互接口。用户通过文档视图结构可实现数据的传输、编辑、读取和保存等。但文档、视图以及和应用程序框架的相关部分之间还包含了一系列分厂复杂的相互作用。切分窗口及一档多视是文档和视图相互作用的典型实例。
(一)文档视图结构
正常情况下,MFC应用程序用一种编程模式使程序中数据与它的显示形式和用户交互分离开来这种模式就是“文档视图结构”。 一般情况下,采用文档/视结构的应用程序至少应由以下对象组成:
。应用程序是一个CwinApp派生对象,它充当全部应用程序的容器。应用程序沿消息映射网络分配消息给它的所有子程序。
。框架窗口是一CfrmeWnd派生对象。
。文档是一个CDocument派生对象,它存储应用程序的数据,并把这些信息提供给应用程序的其余部分。
。视窗是Cview派生对象,它与其父框架窗口用户区对齐。视窗接受用户对应用程序的输入并显示相关联的文档数据。
(二)文档与视图的相互作用
文档视图结构能方便地实现文档和视图的相互作用。通常它们是通过几个重要成员函数相互作用的。
视对象只有一个与之相联系的文档对象,它所包含的CView::GetDocument函数允许应用在视中得到与之相联系的文档,据此,应用程序可以对文档类成员函数及公共数据成员进行访问。如果视对象接受到了一条消息,表示用户在编辑控制中输入了新的数据,此时,视就必须通知文档对象对其内部数据进行相应的更新。
如果文档数据发生了变化,则所有的视都必须被通知到,以便它们能够对所显示的数据进行相应的更新。CDocument::UpdateAllViews函数即可完成此功能。当该函数被调用时,派生视类的CView::OnUpdate函数被触发。通常OnUpdate函数要对文档进行访问,读取文档数据,然后再对视的数据成员或控制进行更新,以便反映出文档的变化。另外,还可以利用OnUpdate函数使视的部分客户区无效,以便触发Cview::OnDraw函数,利用文档数据来重新对窗口进行绘制。
(三)切分窗口
一个文档可以有多个视,切分窗口即是表示多视的一种方法。 切分窗口是通过类CSplitterWnd来表示的,对Window来说,CSplitterWnd对象是一个真正的窗口,它完全占据了框架窗口的客户区域,而视窗口则占据了切分窗口的窗片区域。切分窗口并不参与命令传递机制,(窗片中)活动的视窗从逻辑上来看直接被连到了它的框架窗口中。切分窗口可以分为静态和动态两种。利用CSplitterWnd成员函数用户可以在文档应用程序的文档窗口中添加动态或静态切分功能。
【例Ex_SplitSDI】 将单文档应用程序中的文档窗口静态分成3*2个窗格。
将单文档应用程序中的文档窗口静态分成3*2个窗格的步骤如下:
(1)用MFC AppWizard创建一个默认的单文档应用程序Ex_SplitSDI。
(2)打开框架窗口类MainFrm.h头文件,为CmainFrame类添加一个保护型的切分窗口的数据成员,如以下定义:
protected: //control bar embedded members
CStatusBar m_wndStatusBar;
CtoolBar m_wndToolBar;
CsplitterWnd m_wndSplitter;
(3)用MFCClassWizard 创建一个新的视图类CDemoView(基类为CView)用于与静态切分的窗格相关联。
(4)用MFC ClassWizard为CMainFrame类添加OnCreateClient(当主框架窗口客户区创建的时候自动调用该函数)函数重载,并添加下列代码:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs,CcreateContext*pContext)
{
CRect rc;
GetClientRect(rc);
CSize paneSize(rc.Width()/2-16,rc.Height()/3-16);
m_wndSplitter.CreateStatic(this,3,2);
m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CDemoView),
paneSize,pContext);
m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CDemo View),
paneSize,pContext);
m_wndSplitter.CreateView(1,0,RUNTIME_CLASS(CDemo View),
paneSize,pContext);
m_wndSplitter.CreateView(1,1,RUNTIME_CLASS(CDemoView),
paneSize,pContext);
m_wndSplitter.CreateView(2,0,RUNTIME_CLASS(CDemo View),
paneSize,pContext);
m_wndSplitter.CreateView(2,1,RUNTIME_CLASS(CDemo View),
paneSize,pContext);
return TRUE;
}
(5)在MainFrm.cpp源文件的开始处,添加视图类CDemoView的包含文件:
#include“DemoView.h”
(6)编译并运行。
动态切分窗口的创建过程比静态切分简单得多,它不需要重新为窗格制定其他视图类。
动态切分窗口的所有窗格共享同一个视图。若在文档窗口中添加动态切分功能,除了上述方法外,还可在MFC AppWizard 创建文档应用程序的“Step 4”对话框中单击“高级”按钮,通过选中“Advanced Options”对话框 Windows Styles页面中的“应用拆分窗体”来创建,或是通过添加切分窗口组建来创建。
(四)一档多视
多数情况下,一个文档对应于一个视图,但有时一个文档可能对应于多个视图这种情况称之为“一档多视”。
MFC对于“一档多视”提供下列3个模式:
(1)在各自MDI文档窗口中包含同一个视图类的多个视图对象。用户有时需要应用程序能为同一个文档打开另一个文档窗口,以便能同时使用两个文档窗口来查看文档的不同部分内容。用MFC AppWizard 创建的多文档应用程序支持这种模式,当用户选择“窗口”菜单的“新建窗口”命令式,系统就会为第一个文档窗口创建一个副本。
(2)在同一个文档窗口中包含同一视图类的多个视图对象。这种模式实际上是使用“切分窗口”机制使SDI应用程序具有多视的特征。
(3)在单独一个文档窗口中包含不同视图类的多个视图对象。在该模式下,多个视图共享同一个文档窗口。它有点像“切分窗口”,但由于视图可有不同的视图类构造,所以同一个文档可以有不同的显示方法。例如,同一个文档可同时有文字显示方式及图形显示方式的视图。
在“一档多视“中,几个视图之间的数据传输是通过 Cdocument::UpdateAllViews 和Cview::OnUpdate的相互作用来实现的,而且,为了避免传输的相互干涉,采用提示标识符来区分。而为了能及时更新并保存文档数据,相应的数据成员应在用户文档类中定义。这样,由于所有的视图类都可与文档类进行交互,因而可以共享这些数据。