MFC文档视图架构编程.docx

上传人:b****7 文档编号:9561274 上传时间:2023-02-05 格式:DOCX 页数:44 大小:323.06KB
下载 相关 举报
MFC文档视图架构编程.docx_第1页
第1页 / 共44页
MFC文档视图架构编程.docx_第2页
第2页 / 共44页
MFC文档视图架构编程.docx_第3页
第3页 / 共44页
MFC文档视图架构编程.docx_第4页
第4页 / 共44页
MFC文档视图架构编程.docx_第5页
第5页 / 共44页
点击查看更多>>
下载资源
资源描述

MFC文档视图架构编程.docx

《MFC文档视图架构编程.docx》由会员分享,可在线阅读,更多相关《MFC文档视图架构编程.docx(44页珍藏版)》请在冰豆网上搜索。

MFC文档视图架构编程.docx

MFC文档视图架构编程

MFC文档/视图架构编程

理解了MFC文档视图类的意义及它们纵横交错的关系也就理解了“文档/视图”结构的基本概念,在此基础上,我们再进一步研究“文档/视图”结构的MFC程序消息流动的方向,这样就完全彻底明白了基于"文档/视图"结构MFC程序的“生死因果”。

“文档/视图”结构是MFC中结构最为复杂,体系最为庞大,而又最富有特色的部分,其中涉及到应用、文档模板、文档、视图、SDI窗口、MDI框架窗口、MDI子窗口等多种不同的类,如果不了解这些类及其盘根错节的内部联系的话,就不可能编写出高水平的文档/视图程序。

  学习"文档/视图"结构的意义还不只于其本身,通过该架构的学习,一步步领略MFC设计者的神功奥妙,也将进一步增强我们自身对庞大程序框架的把握能力。

  一个优秀的程序员是可以写出一个个优秀函数的程序员,而一个优秀的系统设计师则需从全局把握软件的架构,分析和学习"文档/视图"结构将是我们成为软件系统设计师之旅的一个重要阶段。

第一讲基本概念

  MFC引入了"文档/视图"结构的概念,理解这个结构是编写基于MFC编写复杂VisualC++程序的关键。

MFC"文档/视图"结构被认为是一种架构,关于什么是架构,这是个"仁者见仁,智者见智"的问题。

引言

  MFC引入了"文档/视图"结构的概念,理解这个结构是编写基于MFC编写复杂VisualC++程序的关键。

"文档/视图"中主要涉及到四种类:

  

(1)文档模板:

classCDocTemplate;//templatefordocumentcreation

classCSingleDocTemplate;//SDIsupport

classCMultiDocTemplate;//MDIsupport

  

(2)文档:

classCDocument;//maindocumentabstraction

  (3)视图:

//viewsonadocument

classCView;//aviewonadocument

classCScrollView;//ascrollingview

  (4)框架窗口:

//framewindows

classCFrameWnd;//standardSDIframe

classCMDIFrameWnd;//standardMDIframe

classCMDIChildWnd;//standardMDIchild

classCMiniFrameWnd;//half-heightcaptionframewnd

  理解了这4个类各自的意义及它们纵横交错的关系也就理解了"文档/视图"结构的基本概念,在此基础上,我们还需要进一步研究"文档/视图"结构的MFC程序消息流动的方向,这样就完全彻底明白了基于"文档/视图"结构MFC程序的"生死因果"。

  出于以上考虑,本文这样组织了各次连载的内容:

  第1次连载进行基本概念的介绍,第2~5次连载分别讲述文档模板、文档、视图和框架窗口四个类的功能和主要函数,连载6则综合阐述四个类之间的关系,接着以连载7讲解消息流动的方向,最后的连载8则以实例剖析连载1~7所讲述的所有内容。

  本文所有的代码基于WIN32平台开发,调试环境为VisualC++6.0。

在本文的连载过程中,您可以通过如下方式联系作者(热忱欢迎读者朋友对本文的内容提出质疑或给出修改意见):

  作者email:

21cnbao@(可以来信提问,笔者将力求予以回信解答);

  另外,对本文的转载请务必注明作者和出处。

未经同意,不得用于任何形式的商业目的。

  架构

  MFC"文档/视图"结构被认为是一种架构,关于什么是架构,这是个"仁者见仁,智者见智"的问题。

在笔者看来,成其为架构者,必具备如下两个特性:

  

(1)它是一种基础性平台,是一个模型。

通过这个平台、这个模型,我们在上面进一步修饰,可以得到无穷无尽的新事物。

譬如,建筑学上的钢筋混凝土结构、ISO(国际标准化组织)的OSI(开放式系统互连)七层模型。

架构只是一种基础性平台,不同于用这个架构造出的实例。

钢筋混凝土结构是架构,而用钢筋混凝土结构造出的房子就不能称为架构。

  这个特性强调了架构的外部特征,即架构具有可学习、可再生、可实例化的特点,是所有基于该架构所构造实例的共性,是贯串在它们体内的一根"筋",但各个基于该架构所构造的实例彼此是存在差异的。

  

(2)它是一个由内部有联系的事物所组成的一个有机整体。

架构中的内部成员不是彼此松散的,并非各自"占山为王",它们歃血为盟,紧密合作,彼此都有明确的责任和分工,因此共同构筑了一个统一的基础性平台、一个统一的模型。

譬如,OSI模型从物理层到应用层进行了良好的合作,虽然内部包含了复杂的多个层次,但仍然脉络清晰。

  由此可见,架构的第2个特性是服务于第1个特性的。

理解架构,关键是理解以上两个特性。

而针对特定的"文档/视图"结构,则需理解如下两个问题:

  

(1)学习这个架构,并学会在这个架构上造房子(编写基于"文档/视图"结构的程序);

  

(2)理解这个架构内部的工作机理(文档模板、文档、视图和框架窗口四个类是如何联系为一个有机整体的),并在造房子时加以灵活应用(重载相关的类)。

  在这里,我们再引用几位专家(或企业)关于架构的定义以供读者进一步参考:

Thekeyideasofacommercialapplicationframework:

agenericapponsteroidsthatprovidesalargeamountofgeneral-purposefunctionalitywithinawell-planned,welltested,cohesivestructure.

(Applicationframeworkis)anextendedcollectionofclassesthatcooperatetosupportacompleteapplicationarchitectureorapplicationmodel,providingmorecompleteapplicationdevelopmentsupportthanasimplesetofclasslibraries.

――MacApp(Apple'sC++applicationframework)

Anapplicationframeworkisanintegratedobject-orientedsoftwaresystemthatoffersalltheapplication-levelclasses(documents,views,andcommands)neededbyagenericapplication.

Anapplicationframeworkismeanttobeusedinitsentirety,andfostersbothdesignreuseandcodereuse.Anapplicationframeworkembodiesaparticularphilosophyforstructuringanapplication,andinreturnforalargemassofprebuiltfunctionality,theprogrammergivesupcontrolovermanyarchitectural-designdecisions.

――RayValdes

  什么是ApplicationFramework?

Framework这个字眼有组织、框架、体制的意思,ApplicationFramework不仅是一般性的泛称,它其实还是对象导向领域中的一个专有名词。

  基本上你可以说,ApplicationFramework是一个完整的程序模型,具备标准应用软件所需的一切基本功能,像是档案存取、打印预视、数据交换...,以及这些功能的使用接口(工具列、状态列、选单、对话盒)。

如果更以术语来说,ApplicationFramework就是由一整组合作无间的"对象"架构起来的大模型。

喔不不,当它还没有与你的程序产生火花的时候,它还只是有形无体,应该说是一组合作无间的"类别"架构起来的大模型。

  ――侯捷

  最后,要强调的是,笔者之所以用一个较长的篇幅来连载关于"文档/视图"结构的内容,是因为"文档/视图"结构是MFC中结构最为复杂,体系最为庞大,而又最富有特色的部分,其中涉及到应用、文档模板、文档、视图、SDI窗口、MDI框架窗口、MDI子窗口等多种不同的类,如果不了解这些类及其盘根错节的内部联系的话,就不可能编写出高水平的文档/视图程序。

当然,学习"文档/视图"结构的意义还不只于其本身,通过该架构的学习,一步步领略MFC设计者的神功奥妙,也将进一步增强我们自身对庞大程序框架的把握能力。

一个优秀的程序员是可以写出一个个优秀函数的程序员,而一个优秀的系统设计师则需从全局把握软件的架构,分析和学习"文档/视图"结构相信将是我们成为系统设计师之旅的一个有利环节。

第二讲文档模板

  在"文档/视图"架构的MFC程序中,提供了文档模板管理者类CDocManager,由它管理应用程序所包含的文档模板。

本讲的内容,您只需要建立基本的印象。

最初的浅尝辄止是为了最终的深入脊髓!

文档模板管理者类CDocManager

  在"文档/视图"架构的MFC程序中,提供了文档模板管理者类CDocManager,由它管理应用程序所包含的文档模板。

我们先看看这个类的声明:

/////////////////////////////////////////////////////////////////////////////

//CDocTemplatemanagerobject

classCDocManager:

publicCObject

{

 DECLARE_DYNAMIC(CDocManager)

 public:

  //Constructor

  CDocManager();

  //Documentfunctions

  virtualvoidAddDocTemplate(CDocTemplate*pTemplate);

  virtualPOSITIONGetFirstDocTemplatePosition()const;

  virtualCDocTemplate*GetNextDocTemplate(POSITION&pos)const;

  virtualvoidRegisterShellFileTypes(BOOLbCompat);

  voidUnregisterShellFileTypes();

  virtualCDocument*OpenDocumentFile(LPCTSTRlpszFileName);//opennamedfile

  virtualBOOLSaveAllModified();//savebeforeexit

  virtualvoidCloseAllDocuments(BOOLbEndSession);//closedocumentsbeforeexiting

  virtualintGetOpenDocumentCount();

  //helperforstandardcommdlgdialogs

  virtualBOOLDoPromptFileName(CString&fileName,UINTnIDSTitle,

  DWORDlFlags,BOOLbOpenFileDialog,CDocTemplate*pTemplate);

  //Commands

  //Advanced:

processasyncDDErequest

  virtualBOOLOnDDECommand(LPTSTRlpszCommand);

  virtualvoidOnFileNew();

  virtualvoidOnFileOpen();

  //Implementation

 protected:

  CPtrListm_templateList;

  intGetDocumentCount();//helpertocountnumberoftotaldocuments

 public:

  staticCPtrList*pStaticList;//forstaticCDocTemplateobjects

  staticBOOLbStaticInit;//TRUEduringstaticinitialization

  staticCDocManager*pStaticDocManager;//forstaticCDocTemplateobjects

 public:

  virtual~CDocManager();

  #ifdef_DEBUG

   virtualvoidAssertValid()const;

   virtualvoidDump(CDumpContext&dc)const;

  #endif

};

  从上述代码可以看出,CDocManager类维护一个CPtrList类型的链表m_templateList(即文档模板链表,实际上,MFC的设计者在MFC的实现中大量使用了链表这种数据结构),CPtrList类型定义为:

classCPtrList:

publicCObject

{

 DECLARE_DYNAMIC(CPtrList)

 protected:

  structCNode

  {

   CNode*pNext;

   CNode*pPrev;

   void*data;

  };

 public:

  //Construction

  CPtrList(intnBlockSize=10);

  //Attributes(headandtail)

  //countofelements

  intGetCount()const;

  BOOLIsEmpty()const;

  //peekatheadortail

  void*&GetHead();

  void*GetHead()const;

  void*&GetTail();

  void*GetTail()const;

  //Operations

  //getheadortail(andremoveit)-don'tcallonemptylist!

  void*RemoveHead();

  void*RemoveTail();

  //addbeforeheadoraftertail

  POSITIONAddHead(void*newElement);

  POSITIONAddTail(void*newElement);

  //addanotherlistofelementsbeforeheadoraftertail

  voidAddHead(CPtrList*pNewList);

  voidAddTail(CPtrList*pNewList);

  //removeallelements

  voidRemoveAll();

  //iteration

  POSITIONGetHeadPosition()const;

  POSITIONGetTailPosition()const;

  void*&GetNext(POSITION&rPosition);//return*Position++

  void*GetNext(POSITION&rPosition)const;//return*Position++

  void*&GetPrev(POSITION&rPosition);//return*Position--

  void*GetPrev(POSITION&rPosition)const;//return*Position--

  //getting/modifyinganelementatagivenposition

  void*&GetAt(POSITIONposition);

  void*GetAt(POSITIONposition)const;

  voidSetAt(POSITIONpos,void*newElement);

  voidRemoveAt(POSITIONposition);

  //insertingbeforeorafteragivenposition

  POSITIONInsertBefore(POSITIONposition,void*newElement);

  POSITIONInsertAfter(POSITIONposition,void*newElement);

  //helperfunctions(note:

O(n)speed)

  POSITIONFind(void*searchValue,POSITIONstartAfter=NULL)const;

  //defaultstostartingattheHEAD

  //returnNULLifnotfound

  POSITIONFindIndex(intnIndex)const;

  //getthe'nIndex'thelement(mayreturnNULL)

  //Implementation

 protected:

  CNode*m_pNodeHead;

  CNode*m_pNodeTail;

  intm_nCount;

  CNode*m_pNodeFree;

  structCPlex*m_pBlocks;

  intm_nBlockSize;

  CNode*NewNode(CNode*,CNode*);

  voidFreeNode(CNode*);

 public:

  ~CPtrList();

  #ifdef_DEBUG

   voidDump(CDumpContext&)const;

   voidAssertValid()const;

  #endif

  //localtypedefsforclasstemplates

  typedefvoid*BASE_TYPE;

  typedefvoid*BASE_ARG_TYPE;

};

很显然,CPtrList是对链表结构体

structCNode

{

 CNode*pNext;

 CNode*pPrev;

 void*data;

};

  本身及其GetNext、GetPrev、GetAt、SetAt、RemoveAt、InsertBefore、InsertAfter、Find、FindIndex等各种操作的封装。

  作为一个抽象的链表类型,CPtrList并未定义其中节点的具体类型,而以一个void指针(structCNode中的void*data)巧妙地实现了链表节点成员具体类型的"模板"化。

很显然,在VisualC++6.0开发的年代,C++语言所具有的语法特征"模板"仍然没有得到广泛的应用。

而CDocManager类的成员函数

virtualvoidAddDocTemplate(CDocTemplate*pTemplate);

virtualPOSITIONGetFirstDocTemplatePosition()const;

virtualCDocTemplate*GetNextDocTemplate(POSITION&pos)const;

  则完成对m_TemplateList链表的添加及遍历操作的封装,我们来看看这三个函数的源代码:

voidCDocManager:

:

AddDocTemplate(CDocTemplate*pTemplate)

{

 if(pTemplate==NULL)

 {

  if(pStaticList!

=NULL)

  {

   POSITIONpos=pStaticList->GetHeadPosition();

   while(pos!

=NULL)

   {

    CDocTemplate*pTemplate=(CDocTemplate*)pStaticList->GetNext(pos);

    AddDocTemplate(pTemplate);

   }

   deletepStaticList;

   pStaticList=NULL;

  }

  bStaticInit=FALSE;

 }

 else

 {

  ASSERT_VALID(pTemplate);

  ASSERT(m_templateList.Find(pTemplate,NULL)==NULL);//mustnotbeinlist

  pTemplate->LoadTemplate();

  m_templateList.AddTail(pTemplate);

 }

}

POSITIONCDocManager:

:

GetFirstDocTemplatePosition()const

{

 returnm_templateList.GetHeadPosition();

}

CDocTemplate*CDocManager:

:

GetNextDocTemplate(POSITION&pos)const

{

 return(CDocTemplate*)m_templateList.GetNext(pos);

}

第三讲文档

  在"文档/视图"架构的MFC程序中,文档是一个CDocument派生对象,它负责存储应用程序的数据,并把这些信息提供给应用程序的其余部分。

  1、文档类CDocument

  在"文档/视图"架构的MFC程序中,文档是一个CDocument派生对象,它负责存储应用程序的数据,并把这些信息提供给应用程序的其余部分。

CDocument类对文档的建立及归档提供

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 药学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1