MFC界面编程基础(16):文档、视图、框架 您所在的位置:网站首页 人力资源视图模板 MFC界面编程基础(16):文档、视图、框架

MFC界面编程基础(16):文档、视图、框架

2024-07-11 02:24| 来源: 网络整理| 查看: 265

上一篇:MFC界面编程基础(15):程序举例+屏蔽或接收键盘事件下一篇:MFC界面编程基础(17):文档序列化

MFC应用程序模型历经多年以有了相当大的发展。有一个时期,它只是个使用应用程序对象和主窗口对象的简单模型。在这个模型中,应用程序的数据作为成员变量保持在框架窗口类中,在框架窗口的客户区中,该数据被提交显示器。随着MFC2.0的问世,一种应用程序结构的新方式----MFC文档/视结构出现了。在文档/视图结构中,CFrameWnd繁重的任务被委派给几个不同类,实现了数据存储和显示的分离。

文档/视图应用程序组成

一般情况下,采用文档/视结构的应用程序至少应由以下对象组成:

应用程序是一个CWinApp派生对象,它充当全部应用程序的容器。应用程序沿消息映射网络分配消息给它的所有子程序。框架窗口是一CFrmeWnd派生对象。文档是一个CDocument派生对象,它存储应用程序的数据,并把这些信息提供给应用程序的其余部分。视窗是CView派生对象,它与其父框架窗口用户区对齐。视窗接受用户对应用程序的输入并显示相关联的文档数据。

通常,应用程序数据存在于简单模型中的框架窗口中。在文档/视方式中,该数据移入称为document的独立数据对象。当然,文档不一定是文字,文档是可以表现应用程序使用的数据集的抽象术语。而用户输入处理及图形输出功能从框架窗口转向视图。单独的视窗完全遮蔽框架窗口的客户区,这意味着即使程序员直接绘画至框架窗口的客户区,视图仍遮蔽绘画,在屏幕上不出现任何信息。所以输出必须通过视图。框架窗口仅仅是个视图容器。

CDocument类对文档的建立及归档提供支持并提供应用程序用于控制其数据的接口。MDI应用程序可以处理多个类型的文档,每个类型的文档拥有一个相关联的文档模板对象。文档对象驻留在场景后面,提供由视图对象显示的信息。文档至少有一个相关联的视图。视图只能与一个文档相关联。

在文档/视方式中,对象的建立是由文档模板来管理的,它是CDocTemplate派生对象,建立并维护框架窗口,文档及视。

总之,在文档/视模式中,文档和视图是分离的,即:文档用于保存数据,而视图是用来显示这些数据。文档模板维护它们之间的关西。这种文档/视结构在开发大型软件项目时特别有用。

文档、视图、框架之间的关联.

MFC SDI/MDI 中的核心就在于文档、视图、框架之间的关联,形成了一个有机的可运作的整体。 MFC 提供了默认的关联关系,但是在实际的项目开发中很多时候需要动态进行他们的之间的关联。

与文档/视结构有关的各种类之间的关系

CWinApp对象拥有并控制文档模板,后者产生文档、框架窗口及视窗。这种相互关系如图所示: 在这里插入图片描述

从用户的角度来看,“视”实际上是一个普通的窗口。像其他基于Widnows应用的窗口一样,人们可以改变它的尺寸,对它进行移动,也可以随时关闭它。若从程序员的角度来看,视实际上是一个从MFC类库中的CView类所派生出的类的对象。文档对象是用来保存数据的,而视对象是用来显示数据的,并且允许对数据进行编辑。SDI或MDI的文档类是由CDocument类派生出来的,它可以有一个或多个视类,而这些视类最终都是由CView类派生出来的。视对象只有一个与之相联系的文档对象,它所包含的 CView::GetDocument函数允许应用在视中得到与之相联系的文档, 据此,应用程序可以对文档类成员函数及公共数据成员进行访问。如果视对象接受到了一条消息,表示用户在编辑控制中输入了新的数据,此时,视就必须通知文档对象对其内部数据进行相应的更新。

如果文档数据发生了变化,则所有的视都必须被通知到,以便它们能够对所显示的数据进行相应的更新。CDocument::UpdateAllViews函数即可完成此功能。当该函数被调用时,派生视类的CView::OnUpdate函数被触发。通常OnUpdate函数要对文档进行访问,读取文档数据,然后再对视的数据成员或控制进行更新,以便反映出文档的变化。另外,还可以利用OnUpdate函数使视的部分客户区无效,以便触发CView::OnDraw函数,利用文档数据来重新对窗口进行绘制。Invalidate()函数也可以使当前窗口无效,导致窗口重绘。

MDI中的指针列表 在MDI应用程序中,可以处理多个文档类型,即多个文档模板,每个模板又可以有多个文档,每个文档又可以多视显示。为管理方便,上一级往往保留了下一级的指针列表。如下图所示: 在这里插入图片描述

MDI中的存取关系 在这里插入图片描述 解释如下:

①: 每个应用程序类(CWinApp的派生类)都保留并维护了一份所有文档模板的指针列表,这是一个链表结构。应用程序为所要支持的每个文档类型动态分配一个CMultiDocTemplate 对象,

CMultiDocTemplate(UINT nIDResource, CRuntimeClass * pDocClass, CRuntimeClass * pFrameClass, CRuntimeClass * pViewClass );

并在应用程序类的CWinApp::InitInstance成员函数中将每个CMultiDocTemplate对象传递给CWinApp::AddDocTemplate。 该函数将一个文档模板加入到应用程序可用文档模板的列表中。函数原形为:

void AddDocTemplate(CdocTemplate * pTemplate);

应用程序可以用CWinApp::GetFirstDocTemplatePostion获得应用程序注册的第一个文档模板的位置,利用该值来调用CWinApp::GetNextDocTemplate函数,获得第一个CDocTemplate对象指针。函数原形如下:

POSITION GetFirstDocTemplate( ) const; CDocTemplate *GetNextDocTemplate( POSITION & pos ) const;

第二个函数返回由pos 标识的文档模板。POSITION是MFC定义的一个用于迭代或对象指针检索的值。通过这两个函数,应用程序可以遍历整个文档模板列表。如果被检索的文档模板是模板列表中的最后一个,则pos参数被置为NULL。 使用 MFC 类向导生成 MFC SDI/MDI 程序,在 App 类的 InitInstance ()方法中有如下代码(假设 Project 名称均为 Test ): SDI (单文档界面)中

CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CTestDoc), RUNTIME_CLASS(CMainFrame),// main SDI frame window RUNTIME_CLASS(CTestView) ); AddDocTemplate(pDocTemplate);

MDI(多文档界面) 中

CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate( IDR_TESTTYPE, RUNTIME_CLASS(CTestDoc), RUNTIME_CLASS(CChildFrame), // custom MDI child frame RUNTIME_CLASS(CTestView) ); AddDocTemplate(pDocTemplate);

这里通过 CDocTemplate (无论是 SDI 中的 CSingleDocTemplate 还是 MDI 中的 CMultiDocTemplate )的构造函数,将文当、视图和框架( SDI 中与主框架, MDI 中与自框架)关联在一起了,形成了一个整体。

②: 一个文档模板可以有多个文档,每个文档模板都保留并维护了一个所有对应文档的指针列表。应用程序可以用CDocTemplate::GetFirstDocPosition函数获得与文档模板相关的文档集合中第一个文档的位置,并用POSITION值作为CDocTemplate::GetNextDoc的参数来重复遍历与模板相关的文档列表。函数原形为:

viaual POSITION GetFirstDocPosition( ) const = 0; isual CDocument *GetNextDoc(POSITION & rPos) const = 0;

如果列表为空,则rPos被置为NULL. ③: 在文档中可以调用CDocument::GetDocTemplate获得指向该文档模板的指针。函数原形如下:

CDocTemplate * GetDocTemplate ( ) const;

如果该文档不属于文档模板管理,则返回值为NULL。 ④: 一个文档可以有多个视图。每一个文档都保留并维护一个所有相关视图的列表。CDocument::AddView将一个视图连接到文档上,将该视图加入到文档相联系的视图的列表中,并将视图的文档指针指向该文档。当有File/New、File/Open、Windows/New或Window/Split的命令而将一个新创建的视图的对象连接到文档上时, MFC会自动调用该函数,框架通过文档/视图的结构将文档和视图联系起来。当然,程序员也可以根据自己的需要调用该函数。

virtual POSITION GetFirstViewPosition( ) const; virtual CViw * GetNextView( POSITION &rPosition) cosnt;

应用程序可以调用CDocument::GetFirstViewPosition返回与调用文档相联系的视图的列表中的第一个视图的位置,并调用CDocument::GetNextView返回指定位置的视图,并将rPositon的值置为列表中下一个视图的POSITION值。如果找到的视图为列表中的最后一个视图,则将rPosition置为NULL.

当在文档上新增一个视图或删除一个视图时,MFC会调用OnChangeViewList函数。如果被删除的视图是该文档的最后一个视图,则删除该文档。

⑤: 一个视图只能有一个文档。在视图中,调用CView::GetDocument可以获得一个指向视图的文档的指针。函数原形如下:

CDocument *GetDocument ( ) const;

如果该视图没有与任何文档相连接,则返回NULL. ⑥: MDI框架窗口通过调用CFrameWnd::GetActiveDocument 可以获得与当前活动的视图相连的CDocument 指针。函数原形如下:

virtual CDocument * GetActiveDocument( );

⑦: 通过调用CFrameWnd::GetActiveView 可以获得指向与CFrameWnd框架窗口连接的活动视图的指针,如果是被CMDIFrameWnd框架窗口调用,则返回NULL。MDI框架窗口可以首先调用MDIGetActive找到活动的MDI子窗口,然后找到该子窗口的活动视。函数原形如下:

virtual Cdocument * GetActiveDocument( );

⑧: MDI框架窗口通过调用CFrameWnd::GetActiveFrame, 可以获得一个指向MDI框架窗口的活动多文档界面子窗口的指针。 ⑨: CMDIChildWnd调用GetMDIFrame获得MDI框架窗口(CMDIFrameWnd)。 ⑩: CWinApp 调用AfxGetMainWnd得到指向应用程序的活动主窗口的指针。

遍历整个文档模板、文档和视图

下面一段代码,就是利用CDocTemplate、CDocument和CView之间的存取关系,遍历整个文档模板、文档以及视图。

//获取应用程序的对象指针 CMyApp * pMyApp = (CMyApp *)AfxGetApp(); POSITION p = pMyApp->GetFirstDocTemplatePosition(); while(p!= NULL) { CDocTemplate * pDocTemplate = pMyApp->GetNextDocTemplate(p); POSITION p1 = pDocTemplate->GetFirstDocPosition(); while(p1 != NULL) { CDocument * pDocument = pDocTemplate->GetNextDoc(p1); POSITION p2 = pDocument->GetFirstViewPosition(); while(p2 != NULL) { CView * pView = pDocument->GetNextView(p2); } } } MFC SDI/MDI 各个类之间的互访

在实际项目开发中用的最多就是各个类之间的互访问,这里将网络上和书籍中提到的做了一个总结,也是在实际开发中比较常用的。 在这里插入图片描述

上一篇:MFC界面编程基础(15):程序举例+屏蔽或接收键盘事件下一篇:MFC界面编程基础(17):文档序列化


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有