MFC"
文档/视图"结构被认为是一种架构,关于什么是架构,这是个"仁者见仁,智者见智"的问题。称其为架构者,必具备如下两个特性:
(1)它是一种基础性平台,是一个模型。通过这个平台、这个模型,可以得到无穷无尽的新事物。譬如,建筑学上的钢筋混凝土结构、ISO(国际标准化组织)的OSI(开放式系统互连)七层模型。架构只是一种基础性平台,不同于用这个架构造出的实例。钢筋混凝土结构是架构,而用钢筋混凝土结构造出的房子就不能称为架构。
这个特性强调了架构的外部特征,即架构具有可学习、可再生、可实例化的特点,是所有基于该架构所构造实例的共性,是贯串在它们体内的一根"筋",但各个基于该架构所构造的实例彼此是存在差异的。
(2)它是一个由内部有联系的事物所组成的一个有机整体。架构中的内部成员不是彼此松散的,并非各自"占山为王",它们紧密合作,彼此都有明确的责任和分工,因此共同构筑了一个统一的基础性平台、一个统一的模型。譬如,OSI模型从物理层到应用层进行了良好的合作,虽然内部包含了复杂的多个层次,但仍然脉络清晰。
由此可见,架构的第2个特性是服务于第1个特性的。理解架构,关键是理解以上两个特性。而针对特定的"文档/视图"结构,则需理解如下两个问题:
(1)学习这个架构,并学会在这个架构上造房子(编写基于"文档/视图"结构的程序);
(2)理解这个架构内部的工作机理(文档模板、文档、视图和框架窗口四个类是如何联系为一个有机整体的),并在造房子时加以灵活应用(重载相关的类)。
我们再引用几位专家关于架构的定义以供读者进一步参考:
什么是Application Framework?Framework 这个字眼有组织、框架、体制的意思,Application Framework 不仅是一般性的泛称,它其实还是对象导向领域中的一个专有名词。
基本上可以说,Application Framework 是一个完整的程序模型,具备标准应用软件所需的一切基本功能,像是档案存取、打印预视、数据交换...,以及这些功能的使用接口(工具列、状态列、选单、对话盒)。如果更以术语来说,Application Framework 就是由一整组合作无间的"对象"架构起来的大模型。当它还没有与我们的程序产生火花的时候,它还只是有形无体,应该说是一组合作无间的"类别"架构起来的大模型。
"文档/视图"中主要涉及到四种类:
(1)文档模板:
class CDocTemplate; // template for document creation
class CSingleDocTemplate; // SDI support
class CMultiDocTemplate; // MDI support
(2)文档:
class CDocument; // main document abstraction
(3)视图:
// views on a document
class CView; // a view on a document
class CScrollView; // a scrolling view
(4)框架窗口:
// frame windows
class CFrameWnd; // standard SDI frame
class CMDIFrameWnd; // standard MDI frame
class CMDIChildWnd; // standard MDI child
class CMiniFrameWnd; // half-height caption frame wnd
模板、文档、视图、框架的关系
(1)文档保留该文档的视图列表和指向创建该文档的文档模板的指针;文档至少有一个相关联的视图,而视图只能与一个文档相关联。
(2)视图保留指向其文档的指针,并被包含在其父框架窗口中;
(3)文档框架窗口(即包含视图的MDI子窗口)保留指向其当前活动视图的指针;
(4)文档模板保留其已打开文档的列表,维护框架窗口、文档及视图的映射;
(5)应用程序保留其文档模板的列表。
文档、文档模板、视图和框架类的互相访问
(1)它是一种基础性平台,是一个模型。通过这个平台、这个模型,可以得到无穷无尽的新事物。譬如,建筑学上的钢筋混凝土结构、ISO(国际标准化组织)的OSI(开放式系统互连)七层模型。架构只是一种基础性平台,不同于用这个架构造出的实例。钢筋混凝土结构是架构,而用钢筋混凝土结构造出的房子就不能称为架构。
这个特性强调了架构的外部特征,即架构具有可学习、可再生、可实例化的特点,是所有基于该架构所构造实例的共性,是贯串在它们体内的一根"筋",但各个基于该架构所构造的实例彼此是存在差异的。
(2)它是一个由内部有联系的事物所组成的一个有机整体。架构中的内部成员不是彼此松散的,并非各自"占山为王",它们紧密合作,彼此都有明确的责任和分工,因此共同构筑了一个统一的基础性平台、一个统一的模型。譬如,OSI模型从物理层到应用层进行了良好的合作,虽然内部包含了复杂的多个层次,但仍然脉络清晰。
由此可见,架构的第2个特性是服务于第1个特性的。理解架构,关键是理解以上两个特性。而针对特定的"文档/视图"结构,则需理解如下两个问题:
(1)学习这个架构,并学会在这个架构上造房子(编写基于"文档/视图"结构的程序);
(2)理解这个架构内部的工作机理(文档模板、文档、视图和框架窗口四个类是如何联系为一个有机整体的),并在造房子时加以灵活应用(重载相关的类)。
我们再引用几位专家关于架构的定义以供读者进一步参考:
什么是Application Framework?Framework 这个字眼有组织、框架、体制的意思,Application Framework 不仅是一般性的泛称,它其实还是对象导向领域中的一个专有名词。
基本上可以说,Application Framework 是一个完整的程序模型,具备标准应用软件所需的一切基本功能,像是档案存取、打印预视、数据交换...,以及这些功能的使用接口(工具列、状态列、选单、对话盒)。如果更以术语来说,Application Framework 就是由一整组合作无间的"对象"架构起来的大模型。当它还没有与我们的程序产生火花的时候,它还只是有形无体,应该说是一组合作无间的"类别"架构起来的大模型。
"文档/视图"中主要涉及到四种类:
(1)文档模板:
class CDocTemplate; // template for document creation
class CSingleDocTemplate; // SDI support
class CMultiDocTemplate; // MDI support
(2)文档:
class CDocument; // main document abstraction
(3)视图:
// views on a document
class CView; // a view on a document
class CScrollView; // a scrolling view
(4)框架窗口:
// frame windows
class CFrameWnd; // standard SDI frame
class CMDIFrameWnd; // standard MDI frame
class CMDIChildWnd; // standard MDI child
class CMiniFrameWnd; // half-height caption frame wnd
模板、文档、视图、框架的关系
(1)文档保留该文档的视图列表和指向创建该文档的文档模板的指针;文档至少有一个相关联的视图,而视图只能与一个文档相关联。
(2)视图保留指向其文档的指针,并被包含在其父框架窗口中;
(3)文档框架窗口(即包含视图的MDI子窗口)保留指向其当前活动视图的指针;
(4)文档模板保留其已打开文档的列表,维护框架窗口、文档及视图的映射;
(5)应用程序保留其文档模板的列表。
文档、文档模板、视图和框架类的互相访问
从该对象
|
如何访问其他对象
|
全局函数
|
调用全局函数AfxGetApp可以得到CWinApp应用类指针
|
应用
|
AfxGetApp()->m_pMainWnd
为框架窗口指针;用CWinApp::GetFirstDocTemplatePostion、CWinApp::GetNextDocTemplate来遍历所有文档模板
|
文档
|
调用CDocument::GetFirstViewPosition,CDocument::GetNextView来遍历所有和文档关联的视图;调用CDocument:: GetDocTemplate 获取文档模板指针
|
文档模板
|
调用CDocTemplate::GetFirstDocPosition、CDocTemplate::GetNextDoc来遍历所有对应文档
|
视图
|
调用CView::GetDocument 得到对应的文档指针; 调用CView::GetParentFrame 获取框架窗口
|
文档框架窗口
|
调用CFrameWnd::GetActiveView 获取当前得到当前活动视图指针; 调用CFrameWnd::GetActiveDocument 获取附加到当前视图的文档指针
|
MDI
框架窗口
|
调用CMDIFrameWnd::MDIGetActive 获取当前活动的MDI子窗口(CMDIChildWnd)
|
列举一个例子,综合应用上表中的函数,写一段代码,完成遍历文档模板、文档和视图的功能:
CMyApp *pMyApp = (CMyApp*)AfxGetApp(); //
得到应用程序指针 POSITION p = pMyApp->GetFirstDocTemplatePosition();//得到第1个文档模板 while (p != NULL) //遍历文档模板 { CDocTemplate *pDocTemplate = pMyApp->GetNextDocTemplate(p); POSITION p1 = pDocTemplate->GetFirstDocPosition();//得到文档模板对应的第1个文档 while (p1 != NULL) //遍历文档模板对应的文档 { CDocument *pDocument = pDocTemplate->GetNextDoc(p1); POSITION p2 = pDocument->GetFirstViewPosition(); //得到文档对应的第1个视图 while (p2 != NULL) //遍历文档对应的视图 { CView *pView = pDocument->GetNextView(p2); } } } |
消息流动机制
基于"文档/视图"架构的MFC程序中,用户消息(鼠标、键盘输入等)会先发往视图,如果视图未处理则会发往框架窗口。所以,一般来说,消息映射宜定义在视图中。另外,如果一个应用同时拥有多个视图而当前活动视图没有对消息进行处理则消息也会发往框架窗口。
完整的WM_COMMAND消息的处理顺序是"视图――文档――框架窗口――应用"!