windows编程技术12文档与视图.docx
- 文档编号:4689027
- 上传时间:2022-12-07
- 格式:DOCX
- 页数:50
- 大小:1.56MB
windows编程技术12文档与视图.docx
《windows编程技术12文档与视图.docx》由会员分享,可在线阅读,更多相关《windows编程技术12文档与视图.docx(50页珍藏版)》请在冰豆网上搜索。
windows编程技术12文档与视图
第12章文档与视图
MFC提供了将应用程序的数据与显示分开的文档-视图结构,它为应用程序提供了统一的框架,参见图12-1。
对应的MFC应用程序的有关类及其MFC基类,可以参见2.2.5节的图2-9和图2-10。
MFC的文档-视图结构是MVC模式的一种部分实现。
12.1MVC
图12-1SDI应用程序中的对象
MVC是一种软件架构模式,通过分解程序的不同功能,达到降低程序设计的复杂度、利于程序员专业分工、简化程序的维护和扩展的目的。
MVC是1979年挪威计算机科学家TrygveReenskaug在Xerox(施乐公司)PARC(PaloAltoResearchCenter,帕洛阿尔托研究中心)工作时,为(历史上第二个面向对象程序设计语言和第一个真正的集成开发环境)SmallTalk提出的。
12.1.1概念
MVC(Model-View-Controller,模型—视图—控制器)是一种软件架构模式,它把软件系统分为如下三个基本部分(参见图12-2):
●模型(Model)——数据(库)。
●视图(View)——图形界面(显示/表示)。
●控制器(Controller)——程序功能(算法)。
图12-2MVC模式的关系图
MVC模式的目的是实现一种动态的程序设计,简化对程序的后续修改和扩展,并且使程序某一部分的重复利用成为可能。
除此之外,此模式通过对复杂度的简化,使程序结构更加直观。
软件系统通过对自身基本部份分离的同时,也赋予了各个基本部分应有的功能,专业人员可以通过自身的专长进行分组合作:
数据库专家利用“模型”进行数据管理和数据库设计、界面设计人员利用“视图”进行图形界面设计、而程序员则利用“控制器”编写程序应有的功能(实现算法等等)。
12.1.2层次
模型(Model,数据模型)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。
“模型”有对数据直接访问的权利,例如对数据库的访问。
“模型”不依赖“视图”和“控制器”,也就是说,模型不关心它会被如何显示或是如何被操作。
但是模型中数据的变化一般会通过一种刷新机制被公布。
为了实现这种机制,那些用于监视此模型的视图必须事先在此模型上注册,从而,视图可以了解在数据模型上发生的改变。
(比较:
观察者模式(软件设计模式))
视图(View)视图层能够实现数据有目的的显示(理论上,这不是必需的)。
在视图中一般没有程序上的逻辑。
为了实现视图上的刷新功能,视图需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。
控制器(Controller)控制器起到不同层面间的组织作用,用于控制应用程序的流程。
它处理事件并作出响应。
“事件”包括用户的行为和数据模型上的改变。
12.1.3实现
●SmallTalk
1980年MVC最早被应用于XeroxPARC的面向对象、动态类型、自反射的编程语言SmallTalk-80环境中,运行在首个具有GUI的原型计算机Alto(男高音)上。
●MacApp
1985年Apple将MVC用于其推出的MacOS系统的面向对象的应用程序框架MacApp中,这是MVC首次在商用产品中的实际应用。
●MFC
1993年2月微软在其随VisualC++1.0推出的MFC2.0中,引入了文档-视图(Document/View)架构,它也是一种对于MVC的早期部分实现。
MFC将程序分成视图(View)和文档(Document)两大类,其中的CDocument对应MVC中的数据模型(Model),CView相当于MVC中的视图+控制(View+Controller),再加上应用程序类CWinApp,合成三大项。
但是MFC基本上是一个失败的MVC作品。
由于MFC对Document/View的定义过于模糊,未将Controller(消息映射)部份取出,因此Controller既可置入View也可置入Document,但不管置入哪一方面,都会与View或Document绑死而缺乏弹性。
●JavaEE——Struts
1999年12月Sun推出的JavaEE(JavaEnterpriseEdition,Java企业版,原来叫J2EE)和其他的各种框架不一样,它为模型对象(ModelObjects)定义了一个规范。
典型例子是由CraigMcClanahan于2000年5月所开发的开源JavaEE轻型Web应用框架ApacheStruts。
⏹视图(View)——在JAVAEE应用程序中,视图(View)可能由JSP(JavaServerPage,爪哇服务器网页)承担。
生成视图的代码则可能是Servlet的一部分,特别是在客户端服务端交互的时候。
⏹控制器(Controller)——JAVAEE应用中,控制器可能是一个Servlet。
⏹模型(Model)——模型则是由一个实体Bean来实现。
●.NET——WindowsForms
2002年2月微软所推出的.NET框架中还包含有WinForms(视窗窗体),这个针对视图(View)和控制器(Controller)的模式已被很好地定义,而模型(Model)则留给开发者去设计。
⏹视图(View)——由Form或者Control类继承来的一个类处理视图的职责。
在WinForm这个例子中视图和控制器被编译在同一个类中,这个和ASP.NET不同。
⏹控制器(Controller)——控制器的职责被分割成三部分。
事件(Event)的产生和传输是操作系统的一部分。
在.Net框架中Form和Control类将不同的事件转发给相应的事件处理器。
而事件的处理则在分离的代码中实现。
⏹模型(Model)——就像ASP.NET一样,WinForm不严格需要一个模型。
开发者可以自行选择创建一个模型类,但是很多人选择放弃这一步,直接把事件处理放在控制器里处理任何计算、数据保存等等。
也就是说用模型来包含商业逻辑和数据访问。
●.NET——ASP.NET
2002年2月微软随.NET推出了ASP.NET,针对视图(View)和控制器(Controller)的模式并没有被很好地定义,模型(Model)也留给开发者去设计。
⏹视图(View)——ASPX和ASCX文件被用来处理视图的职责。
在这个设计中视图实际上是从控制器继承而来。
这个和Smalltalk的实施有所不同,在Smalltalk中不同的类都有指针互相指向对方。
⏹控制器(Controller)——控制器的职责被分割成两部分。
事件(Event)的产生和传输是框架的一部分,更明确的说是Page和Control两个类。
而事件的处理则在分离的代码中实现。
⏹模型(Model)——ASP.NET不严格需要一个模型。
开发者可以自行选择创建一个模型类,但是很多人选择放弃这一步,直接把事件处理放在控制器里处理任何计算、数据保存等等。
但用模型来包含商业逻辑和数据访问是可实现的。
2009年4月9日微软推出了ASP.NETMVC1.0,它在ASP.NET3.5运行库之上提供了一个新的MVC架构。
此架构为Web应用程序文件夹(folder)结构定义了一个特别模式,并提供了一个控制器基类来处理“动作(actions)”请求。
ASP.NETMVC2.0也已于2010年3月12日推出,它建立在ASP.NET3.5SP1运行库之上,并且被集成进了2010年4月12日推出的.NET框架4.0和VisualStudio2010之中。
12.2文档-视图体系
文档(document)对应于用户的数据(可以是文本、数值、图像、声音、视频等),它可以从磁盘文件中读入,也可写入磁盘文件,用户还可以创建、修改和管理这些数据。
文档对应的MFC类为CDocument。
视图(view)是一种窗口对象,对应于(主/子)框架窗口的客户区,它负责在屏幕和打印机上显示和输出数据,为用户提供观察、选择、编辑文档数据的交互界面(参见图12-3)。
视图对应的MFC类为CView。
图12-3文档与视图
文档-视图结构有两种主要的方式:
SDI(SingleDocumentInterface,单文档界面)和MDI(MultipleDocumentInterface,多文档界面)。
从MFC7.0起新增加了一种MTDI(MultipleTop-levelDocumentInterface,多顶级文档界面),参见图11-4。
SDI传统子窗口MDI选项卡式MDIMTDI
图11-4不同的文档界面
SDI应用程序只有一个框架窗口(类)和一个视图窗口(对应于框架窗口的客户区),且只有一个文档类,每次只能打开一个文档。
这里的文档和视图一般是一一对应的。
例如Windows中的记事本、写字板和画图等软件,是典型的SDI应用程序。
图12-5一个文档可对应多个视图
MDI应用程序有一个主框架窗口(类),可有任意多个子框架窗口和对应的视图客户区窗口,也可有多个文档类,可以同时打开多个文档/窗口。
这里,每个视图对应于一个文档,而每个文档则可对应于多个视图,参见图12-5。
例如Word2000和IE8,分别是传统和选卡式MDI应用程序。
MTDI类似于MDI,只是MDI中的每个文档视图窗口都是主框架窗口的子窗口(只能位于主框架窗口的客户区内)。
而MTDI的文档视图窗口都是顶层窗口,位于主框架窗口之外。
例如新版Word和老版IE,就是典型的MTDI应用程序。
应用程序的文档-视图结构种类,可以在创建MFC应用程序时,在“MFC应用程序向导”对话框的“应用程序类型”页中设置(默认为MDI),在该对话框页中还可以选择是否具有“文档/视图结构支持”(默认是选中的),参见图12-6。
图12-6MFC应用程序向导中的“文档/视图结构支持”选项
12.2.1文档模板类
图12-7文档模板类的层次结构
文档、框架窗口与视图通过文档模板联系在一起,MFC的文档模板类为CDocTemplate。
对SDI与MDI,它有两个对应的派生类CSingleDocTemplate与CMultiDocTemplate,在MFC功能包中又增加了多文档模板的扩展类CMultiDocTemplateEx,参见图12-7。
它们的构造函数的参数都一样:
C[Single|Multi]DocTemplate[Ex](//文档模板构造函数
UINTnIDResource,//文档类型的资源ID
CRuntimeClass*pDocClass,//派生文档类对象的指针
CRuntimeClass*pFrameClass,//[派生]框架窗口类对象的指针
CRuntimeClass*pViewClass//派生视图类对象的指针
);
CWinApp类创建文档模板的操作分两步进行,首先用文档模板类的构造函数创建一个SDI或MDI文档模板的实例,然后调用CWinApp类的成员函数AddDocument将该模板添加到应用程序的模板列表中。
创建文档模板的操作,一般在派生应用程序类的InitInstance成员函数中完成。
例如(SDI):
BOOLCDrawApp:
:
InitInstance(){
……
//注册应用程序的文档模板。
文档模板
//将用作文档、框架窗口和视图之间的连接
CSingleDocTemplate*pDocTemplate;
pDocTemplate=newCSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CDrawDoc),
RUNTIME_CLASS(CMainFrame),//自定义MDI子框架
RUNTIME_CLASS(CDrawView));
if(!
pDocTemplate)returnFALSE;
AddDocTemplate(pDocTemplate);
……
}
其中,RUNTIME_CLASS宏返回一个指向CRunTimeClass类的指针:
CRuntimeClass*RUNTIME_CLASS(class_name)
又例如(MDI):
BOOLCImageApp:
:
InitInstance(){
……
//注册应用程序的文档模板。
文档模板
//将用作文档、框架窗口和视图之间的连接
CMultiDocTemplate*pDocTemplate;
pDocTemplate=newCMultiDocTemplate(
IDR_BMPTYPE,
RUNTIME_CLASS(CImageDoc),
RUNTIME_CLASS(CChildFrame),//自定义MDI子框架
RUNTIME_CLASS(CImageView));
if(!
pDocTemplate)returnFALSE;
AddDocTemplate(pDocTemplate);
pDocTemplate=newCMultiDocTemplate(
IDR_GIFTYPE,
RUNTIME_CLASS(CImageDoc),
RUNTIME_CLASS(CChildFrame),//自定义MDI子框架
RUNTIME_CLASS(CImageView));
if(!
pDocTemplate)returnFALSE;
AddDocTemplate(pDocTemplate);
……
}
可见一个MDI应用程序可有多个MDI模板,每个MDI模板在运行时又可有多个实例,对应于同一模板中同一文档类型/视图类型的多个文档对象/视图窗口,参见图12-8。
图12-8具有两个文档类型的MDI应用程序
12.2.2文档类
所有用户的文档类都是从文档基类CDocument派生的,参见图12-9。
CDocument类的常用成员函数有(其中粗体表示最常用的):
●
图12-9文档类的层次结构
GetFirstViewPosition——获得视图列表中与本文档关联的第一个视图的位置,该位置可用于GetNextView函数,原型为:
virtualPOSITIONGetFirstViewPosition()const;
●GetNextView——返回rPosition所指的视图的指针,获得下一个本文档关联的视图的位置到rPosition中,原型为:
virtualCView*GetNextView(POSITION&rPosition)const;
使用GetFirstViewPosition与GetNextView可遍历文档的所有视图。
●GetTitle——返回文档(窗口)的标题,一般为相关联的文件名,原型为:
constCString&GetTitle()const;
●SetTitle——设置文档(窗口)的标题,原型为:
virtualvoidSetTitle(LPCTSTRlpszTitle);
●GetPathName——返回与文档相关联的文件路径串,无关联文件时返回NULL,原型为:
constCString&GetPathName()const;
●SetPathName——设置存取文档的默认路径(与文档窗口的标题),若bAddToMRU=TRUE,则将该路径添加到最近使用(mostrecentlyused,MRU)文件的列表,原型为:
virtualvoidSetPathName(LPCTSTRlpszPathName,
BOOLbAddToMRU=TRUE);
●IsModified——判断文档在最后一次存储后是否被修改过。
若被修改过,则在用户关闭文档窗口或应用程序时,会提示保存文件,原型为:
BOOLIsModified();
●SetModifiedFlag——设置文档在最后一次存储后是否被修改过,原型为:
voidSetModifiedFlag(BOOLbModified=TRUE);
●UpdateAllViews——在用户通过视图pSender修改了文档数据后,应调用该函数通知所有与文档相关联的其他视图窗口。
若pSender=NULL,则通知与文档相关联的所有视图窗口,该函数会调用每个视图类的OnUpdate成员函数,一般是在调用SetModifiedFlag后调用该函数。
原型为:
voidUpdateAllViews(CView*pSender,LPARAMlHint=0L,
CObject*pHint=NULL);
●Serialize——默认时,派生的文档类会覆盖根类CObject的序列化成员函数Serialize以支持文档的读写,原型为:
virtualvoidSerialize(CArchive&ar);
例如:
voidCTestDoc:
:
Serialize(CArchive&ar){
if(ar.IsStoring()){//写入(对应于选中“文件”菜单中的“保存”项)
//TODO:
addstoringcodehere
ar< }else{//读取(对应于选中“文件”菜单中的“打开”项) //TODO: addloadingcodehere ar>>m_nWidth>>m_nHeight; } } ●LoadStdProfileSettings——在派生应用程序类C*App的InitInstance成员函数中,默认会调用该成员函数来支持MRU文件列表功能,原型为: voidLoadStdProfileSettings(UINTnMaxMRU=_AFX_MRU_COUNT); 其中,_AFX_MRU_COUNT=4,nMaxMRU可取的最大值为_AFX_MRU_MAX_COUNT=16,若nMaxMRU=0,则不支持MRU。 例如: LoadStdProfileSettings(4);//加载标准INI文件选项(包括MRU) LoadStdProfileSettings(10);//自己设置 也可调用应用程序类的成员函数 virtualvoidAddToRecentFileList(LPCTSTRlpszPathName); 来向MRU文件列表中添加指定的文件路径串。 MFC将MRU功能封装在从CObject类派生的CRecentFileList类中。 12.2.3框架窗口类 因为视图窗口是框架窗口的子窗口,位于框架窗口的客户区。 视图窗口本身只是一个没有边框、没有标题条、更没有菜单条和控制条的矩形区域。 视图窗口不能单独存在,必须依附于一个框架窗口,参见图12-10a)。 主框架窗口负责管理标题条、菜单条、控制条、加速键和视图窗口或文档子窗口,参见图12-10b)。 a)框架窗口与视图 b)MDI框架窗口与子窗口 图12-10框架窗口图12-11框架窗口类的层次结构 框架窗口(类)也是通过文档模板(类)与视图(类)及文档(类)联系在一起的。 MFC中框架窗口类为从窗口类CWnd派生的类CFrameWnd,参见图12-11。 SDI应用程序的主框架窗口一般直接以CFrameWnd为基类,例如: classCMainFrame: publicCFrameWnd{ protected: //仅从序列化创建 CMainFrame(); DECLARE_DYNCREATE(CMainFrame) ...... } 图12-12框架窗口类的层次结构 但MDI应用程序的主框架窗口则一般以其派生类CMDIFrameWnd为基类,例如: classCMainFrame: publicCMDIFrameWnd{ DECLARE_DYNAMIC(CMainFrame) public: CMainFrame(); ...... } 而MDI中文档子窗口的框架窗口,则从另一个框架窗口类CMDIChildWnd派生。 例如: classCChildFrame: publicCMDIChildWnd{ DECLARE_DYNCREATE(CChildFrame) public: CChildFrame(); ...... } 12.2.4视图类 视图是文档与用户的接口,为用户提供观察、选择、编辑文档数据的交互界面。 MFC中的视图类为从CWnd派生的CView类及其派生类。 图12-12视图类的层次结构 MFC应用程序的视图类的基类一般为CView,其他常用的视图基类有CScrollView、C[Rich]EditView、CFormView、CHtmlView、(MFC8.0新加的)CWndFormsView和(MFC9.0功能包新加的)CTabView,参见图12-12。 1.CView类 CView是用户视图类的默认基类,也是其他各种MFC视图类的基类。 例如: classCTestView: publicCView{ protected: //仅从序列化创建 CTestView(); DECLARE_DYNCREATE(CTestView) //属性 public: CTestDoc*GetDocument()const; …… //重写 public: virtualvoidOnDraw(CDC*pDC);//重写以绘制该视图 …… protected: CDocument*m_pDocument; //生成的消息映射函数 protected: DECLARE_MESSAGE_MAP() }; 1)CView类的常用成员函数有: CDocument*GetDocument()const;//获得对应文档类对象的指针 virtualvoidOnInitialUpdate();//初始化虚消息响应函数,可覆盖 virtualvoidOnActivateView(BOOLbActivate,CView*pActivateView, CView*pDeactiveView);//当视图窗口被激活或非激活时被调用 virtualvoidOnDraw(CDC*pDC)=0;//纯虚函数,必须覆盖 2)视图类从其基类CWnd继承的常用成员函数有: CDC*GetDC();//获得视图窗口的DC intReleaseDC(CDC*pDC);//释放视图窗口的DC voidGetClientRect(LPRECTlpRect)const;//获得客户区矩形 voidGetWindowRect(LPRECTlpRect)const;//获得窗口矩形 //获得需重绘的最小矩形 BOOLGetUpdateRect(LPRECTlpRect,BOOLbErase=FA
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- windows 编程 技术 12 文档 视图
![提示](https://static.bdocx.com/images/bang_tan.gif)