关于MFC的document/view结构


 关于MFC的document/view结构


MFC之所以能成为application framework,很大的原因就在于其Document/View结构对于快速开发的支持。Document/View很好地划分了程序代码的前台后台,让程序员可以专心于设计数据结构和UI。

  Document即为“资料”,按我理解就是饭店的厨师;而View就是饭店的服务员。View负责点菜和上菜(对用户请求做出直接响应),而Document负责烹饪,即处理用户的要求。

  除了Document和View,还有一个Frame,因为View要放在Frame内部,Frame就是承载View的框架。而三者之间的关系是由Document Template来管理的,一份Document Template管理一个document/frame/view三件组,而一个程序可以有多个document template,多个document template由一个CDocManager对象管理。

  document template

  一个MDI(多文档接口)应用程序使用主框架窗口(main frame window)作为工作区,在工作区里用户可以打开多个文档框架窗口,每一个文档框架窗口用以显示一份文档。

  Document template是用来定义以下三种类之间关系的模板:

  Document(文档)类,从CDocument派生而来,用于处理数据,即所谓数据之体。

  View(视图)类,用于将来自Document类的数据显示出来,可以从CView、CScrollView、CFormView和CEditView类派生,也可以直接使用CEditView类。

  框架窗口(frame window)类,用以包含View。对于MDI程序,可以从CMDIChildWnd派生,也可以直接使用该类。

  MDI应用程序可以支持不止一种文档,而且不同种类的文档可以同时打开(比如一个text和一个bitmap)。对于每一种所支持的文档,应用程序都应该有一份对应的document template进行管理。也就是说你的应用程序支持几种文档,就应该有几个Document template。

  当用户创建新文档的时候,应用程序就会使用document template。如果程序支持的文档种类在一种以上,那么程序框架就会从document templates处取得所有的文档类型名字,显示在File New对话框里。一旦用户选择了文档类型,应用程序就会创建一个document对象,一个frame window对象和一个view对象,并且将它们联系在一起(通过document template)。

  通常程序员不需要使用CMultiDocTemplate的任何成员函数(除了构造函数外)。框架会在内部自动处理CMultiDocTemplate对象。

  为了管理通过相关view对象和frame window对象来构建document的复杂过程,framework使用两种document template类:

  CSingleDocTemplate类用于SDI程序;CMultiDocTemplate类用于MDI程序。一个CSingleDocTemplate在同一时刻只能创建并储存单一种类的一个文档;一个CMultiDocTemplate在同一时刻可以管理单一种类的多个文档。

  有些应用程序支持不止一种文档类型,比如同时支持文本和图形。这种应用程序为每个支持的类型使用单独的document template对象,见下图:

  这个应用程序支持两种文档类型,因此具备两个document template对象。对于每一种文档类型可以打开多个文档,每打开一个文档应用程序就为之创建三个对象:CMyDocument对象用于处理数据,CMyView对象用于显示,CMyFrameWnd用于装载view,但是不管打开多少个同类型文档,负责管理该类型的document template对象只有一个,它负责管理的是上述三个类之间的关系,负责在这三个类的对象创建之时指定它们之间的关系。

  上面说到每打开一个document,会随之一起创建一个view和一个frame window,而这三者的创建工作就是由document template完成的,当用户点击“File/New”或者“File/Open”后,消息发出,被theApp的OnFileNew()接到,但它经过一系列的调用(比较绕)最终调用的是CMultiDocTemplate::OpenDocumentFile(),该函数完成此三对象的创建,其中view的创建又是非常的绕,最终经过一系列的调用由CFrameWnd::CreateView()完成,另外还会调用CView从CWnd继承来的函数Create()用于产生与该view对应的真实窗口。而创建什么种类的document、window、view是在创建document template时由document template的构造函数的参数指定的。下面显示了创建一个CMultiDocTemplate(用以管理MDI的document template)的过程:

  CMultiDocTemplate* pDocTemplate;

  pDocTemplate = new CMultiDocTemplate(IDR_CMyDocTypeTYPE,

  ?? RUNTIME_CLASS(CMyDoc),

  ?? RUNTIME_CLASS(CChildFrame), // custom MDI child frame

  ?? RUNTIME_CLASS(CMyView));

  if (!pDocTemplate)

  ?? return FALSE;

  AddDocTemplate(pDocTemplate);

  传给构造函数的第一个参数是一个资源ID,该资源用于提供该文档类型的菜单、快捷键、按钮等。剩余三个参数用RUN_CLASS()宏提供CMultiDocTemplate创建document/window/view时所需要的类型信息(即对应的RuntimeClass对象,当用户打开一个文件时,document template就可以据此动态创建出document/window/view,这就很好体现了MFC动态创建的用途,关于动态创建是由DECLARE_DYNCREATE()/IMPLEMENT_DYNCREATE()宏实现的),最后用AddDocTemplate()加载此document template,AddDocTemplate()实际上是将document template加到由theApp的一个指针CDocManager* m_pDocManager所维护的document template链表中CDocTemplate有三个成员变量分别持有document/window/view的RuntimeClass对象的指针,另外还有一个资源ID成员。

  Document template对象是被theApp创建的。在theApp的InitInstance()中的一个关键任务就是创建一个或多个适当种类的document template。theApp会在template list中保存指向每一个document template的指针并提供一个接口用于增加document template(AddDocTemplate())。如果你想要支持两个或以上的文档类型,你必须为每个文档类型显式地调用AddDocTemplate()。

  多个Document template是由一个CDocManager对象管理的,很多原本由CWinApp做的关于document template的工作如:AddDocTemplate()、OpenDocumentFile()、NewDocumentFile(),在MFC4.0后都由CDocManager来做了。

 

 

CDocTemplate/CDocment/CFrameWnd/CView之间的指针互指关系

  列出:

  CDocTemplate有指向其余三者RuntimeClass对象的指针:

  ?CRuntimeClass* m_pDocClass;

  ?CRuntimeClass* m_pFrameClass;

  ?CRuntimeClass* m_pViewClass;

  还有指向Document列表的指针:CPtrList m_pDocList;表示一个CDocTemplate可以维护多个同类型文档。

  CDocument有CDocTemplate* m_pDocTemplate回指CDocTemplate;另有CPtrList m_pViewList指向一个view的链表,表示一个Document可以对应多个View。

  CFrameWnd有CView* m_pViewActive指向当前活动在其中的view。

  CView有CDocument* m_pDocument指向对应的Document。

  CDocument/CFrameWnd/CView之间互相操作的函数

  CDocument::UpdateAllViews()—————>CView:OnUpdate()

  CView::GetDocument();

  CView::GetParentFrame();

  CFrameWnd::GetActiveView();

  CFrameWnd::GetActiveDocument();

  View和Document的通信

  程序员通过改写CMyView的如下函数达到View和Document通信的目的:

  CView::OnInitialUpdate():负责view的初始化。

  CView::OnUpdate():Frameword在Document发生变化时调用此函数,此为预留给程序员的“用Document的变化指导View”的接口。

  CView::OnDraw():该函数作为WM_PAINT的间接响应,负责View的更新。

  CDocument::UpdateAllViews()/CView::OnUpdate()这一对函数是命令与执行的关系,调用UpdateAllViews()就会通知所有的View,通知方法就是调用其OnUpdate()。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值