第三章MFC应用程序框架.ppt

上传人:qwe****56 文档编号:70105737 上传时间:2023-01-16 格式:PPT 页数:75 大小:428KB
返回 下载 相关 举报
第三章MFC应用程序框架.ppt_第1页
第1页 / 共75页
第三章MFC应用程序框架.ppt_第2页
第2页 / 共75页
点击查看更多>>
资源描述

《第三章MFC应用程序框架.ppt》由会员分享,可在线阅读,更多相关《第三章MFC应用程序框架.ppt(75页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、第3章MFC应用程序框架l如果把设计Windows应用程序框架所需要的API函数和数据封装成类,便可以利用类的继承性实现代码重用,并在派生过程中对它进行必要的改造,从而快速地获得所需要的类,提高应用程序框架的开发效率。lMFC正是满足上述要求的一个类库,它有一组专门的类,可以快速创建应用程序的框架3.1 早期的应用程序框架及其MFC类l早期的MFC,正如第2章所介绍,在应用程序类中嵌入一个窗口类对象就构成了程序的框架。l尽管比较简单,但它体现了MFC程序的主体结构3.1.1早期的应用程序框架l早期的应用程序框架由两个对象组成:应用程序类CWinApp的派生类对象和窗口类CFrameWnd的派生

2、类对象,后者作为一个成员对象嵌在前者之中。l在应用程序主函数WinMain()中,CWinApp派生类的对象theApp通过调用自己的各个成员函数来完成程序的初始化及消息循环等一系列工作3.1.2 MFC的窗口类l窗口类CFrameWnd是一个重要类,它的对象通常就是应用程序的主窗口。因此作为程序设计人员,必须对它和它的基类有一个比较清楚的了解。lCFrameWnd类由基类CObject经CCmdTarget、CWnd派生而来1.CObject类lCObject类为其派生类不仅提供了程序调试诊断信息输出之通用功能,并且还对运行期对象类型识别(RTTI)、对象的动态创建、对象的序列化提供了相应的

3、支持。l凡是需要具有上述功能的类,必须以CObject或其派生类为基类来派生2.CCmdTarget类l为了支持消息处理,MFC以CObject类为基类派生了CCmdTarget类,并在这个类中封装了窗口函数l凡是希望具有处理Windows消息的能力的类都必须以CCmdTarget类或其派生类为基类来派生3.CWnd类lWindows把应用程序窗口界面上的许多图形元素,例如,控制栏、对话框、视图、属性页和控件等,都看作子窗口l为了对这些窗口类提供应有的通用属性和方法,MFC以CCmdTarget类为基类派生了CWnd类。l凡是以窗口形式为外观并且可以响应消息的类,它们的基类都是CWnd类4.C

4、FrameWnd类l应用程序窗口类CFrameWnd是一个特殊的CWnd类,它或它的派生类对象要承担应用程序主窗口的任务l它除了需要CWnd类的一些通用功能之外,还需要一些特殊功能。l它也是其它子窗口对象的容器3.1.3 CWinApp类lMFC希望把程序的主函数的函数体部分也作为一个对象来处理,为此提供了应用程序类CWinApp,其类的继承关系为:CObject-CCmdTarget-CWinThread-CWinAppl为了支持Windows多线程工作方式,MFC构建了一个线程类CWinThread。在此类中封装了一些用于线程管理的功能函数提醒:lMFC把原来在CWinApp类中定义的lC

5、Wnd*类型的数据成员lm_pMainWnd(指向程序主窗口对象的指针)l放在CWinThread类中定义lCWinApp类中定义了三个可以重写的虚函数lInitApplication()lInitInstance()-程序创建和显示窗口lRun()l程序设计时,必须以CWinApp类为基类派生自己的应用程序类,并根据情况重写InitInstance()3.2 最简单的MFC程序实例l3.2.1 程序的编写l例3-1 使用早期的MFC应用程序框架类设计的一个最简单的Windows应用程序,它只创建一个窗口l通过计算机演示这个最简单的程序的编写l其中需要自己书写的代码如下:l#include l

6、/由CWinApp派生的应用程序类声明lclass MyApp:public CWinAppllpublic:lBOOL InitInstance();l/声明InitInstance(),重写虚函数需要重新 l 声明l;l/定义应用程序类的全局对象lMyApp theApp;l/InitInstance()的实现lBOOL MyApp:InitInstance()llCFrameWnd*pMainWnd=new CFrameWnd;l /创建窗口框架类的对象lpMainWnd-Create(NULL,Basic MFC Application);lpMainWnd-ShowWindow(m_

7、nCmdShow);lpMainWnd-UpdateData();lm_pMainWnd=pMainWnd;lreturn TRUE;l3.2.2 程序主函数的代码l在前面的源文件中,没有看到主函数,那么主函数哪里去了?l主函数是自动生成的。其代码能过调试的过程可以见到3.3 应用程序的文档/视图结构l目前,用MFC设计的Windows应用程序几乎都采用文档/视图结构。l这种新程序框架与原先简单程序框架相比,其最重要的区别是原来的应用程序主窗口对象被拆分窗口框架类CFrameWnd对象、视图类CView类对象和CDocument对象三个对象。3.3.1 文档/视图结构的基本概念l从简单应用程序

8、框架的介绍中可以知道,窗口对象的任务极其繁重:它既要管理窗口本身的一些事务(例如窗口的最大化、最小化、关闭、响应菜单命令等),又要管理应用程序的数据,同时还要负责数据的显示和接受用户区的消息及处理等任务。l随着应用程序规模的扩大,这个矛盾更为突出。l现在窗口框架类CFrameWnd只承担应用程序窗口边框那部分任务,而把程序窗口的用户区那部分功能单独分割出来构建了一个新的类CView类,由它的对象来完成数据的显示、用户区消息的响应和处理等工作;至于程序数据的存储、运算和管理等工作则交给了文档类CDocument对象l上述三个类对象由一叫做文档模板类的对象来统一创建和管理。l应用程序类对象则是上述

9、所有对象的容器和消息传递中心3.3.2 单文档界面和多文档界面结构l有两种类型的文档/视图结构程序:单文档界面(SDI)应用程序和多文档界面(MDI)应用程序l在单文档界面程序中,用户在一个时刻只能操作一个文档,Windows下的NotePad记事本程序就是一个单文档界面程序的例子l多文档界面应用程序允许同时打开和操作多个文档,多文档应用程序提供一个File菜单,往往还提供一个Close菜单项用以关闭当前打开的文档3.4 文档类CDocument的派生类l程序员在用MFC AppWizard 生成应用程序框架时,MFC AppWizard 会自动以文档类CDocument为基类,为应用程序派生

10、一个类名称中含有工程名的文档类,这个派生文档类的主要代码如下(例如,工程名为My)l此派生类从CCmdTarget类派生,所以可以接收来自菜单或工具条发来的命令消息lclass CMyDoc:public CDocumentlprotected:lCMyDoc();lDECLARE_DYNCREATE(CMyDoc)public:lvirtual BOOL OnNewDocument();lvirtual void Serialize(CArchive&ar);public:lvirtual CMyDoc();lDECLARE_MESSAGE_MAP()l;l此类基本上只是个框架,但它是应用程

11、序的数据库,是程序员定义程序数据和对这些数据进行操作的成员函数的地方l文档类派生类中还定义了两个用户可以重写的虚函数,其中比较重要的是Serialize()函数,当用户用菜单对文件进行新建、打开、保存等操作时,应用程序会自动调用这个函数,此函数是程序员编码较多地方3.5 视图类CView的派生类l视图类CView对象没有自己的边框,它的作用是为框架窗口提供用户区。l它把原来窗口框架类承担数据显示和接受用户对用户区操作(消息映射)的代码单独分出来,形成一单独的类。l它的对象是应用程序与用户进行交互的界面,也是程序员编写代码最多的地方l如果使用MFC AppWizard来创建应用程序,向导会自动生

12、成一个含有工程名的CView类的派生类。例如工程名为My,则派生类为CMyView.l此类主要代码为:lClass CMyView:public CViewllProceted:l CMyView();l DECLARE_DYNCRATED(CMyView)lPublic:l CMyDoc*GetDocument();l Virtual void OnDraw(CDC*pDC);l Virtual BOOL PreCreateWindow l (CREATESTRUCT&cs);lProtected:l DECLARE_MESSAGE_MAP()ll视图类有几个重要的成员函数,GetDocum

13、ent()lOnDraw()lPreCreateWindow()l其中最重要的前两个函数l1.GetDocument()l用于获得文档类对象的指针(其返回值是指向文档类对象的指针)。视图类必须通过它来访问文档类对象中的数据l2.OnDraw()l这是一个消息处理函数,其作用是用来更新视图的显示。l系统向这个函数传递一个设备上下文(DC)参数,从而使程序可以使用它来绘图l当应用程序窗口出现变化时,系统自动调用它来重绘窗口l其它窗口也可以向它发重绘视图的消息命令3.6 窗口框架类CFrameWnd的派生类l向导自动生成一个CFrameWnd类的派生类,其名字为CMainFramel类CMainFr

14、ame的工作不太多,框架的大部分工作已经由CFrameWnd类实现,另外,视图显示与用互交互由视图类实现,数据处理由文档类承担,所以这点可以理解l程序员如果想编写自己的框架代码,可修改CFrameWnd类的方法3.7 文档模板类CDocTemplatel为了把视图对象、框架窗口对象和文档对象组装在一起并统一管理,MFC使用了叫做文档模板的抽象类CDocTemplatel由CDocTemplate派生两个类,分别用于单文档程序和多文档程序,即CSingleDocTemplate类lCMultiDocTemplate类单文档模板类的部分代码lclass CSingleDocTemplate:pub

15、lic CDocTemplatellDECLARE_DYNAMIC(CSingleDocTemplate)lpublic:lCSingleDocTemplate(lUINT nIDResource,/程序资源标识lCRuntimeClass*pDocClass,/文档CRuntimeClass*pFrameClass,/窗口框架CRuntimeClass*pViewClass/视图);lprotected:/standard implementationlCDocument*m_pOnlyDoc;l;多文档模板类的部分代码lclass CMultiDocTemplate:public CDoc

16、TemplatellDECLARE_DYNAMIC(CSingleDocTemplate)lpublic:lCSingleDocTemplate(lUINT nIDResource,/程序资源标识lCRuntimeClass*pDocClass,/文档CRuntimeClass*pFrameClass,/窗口框架CRuntimeClass*pViewClass/视图);lprotected:/standard implementationlCPtrList m_docList;/文档链表l;l此两个派生类之间的重要区别在于CSingleDocTemplate中只有一个文档指针,而CMultiD

17、ocTemplate中是一个文档链表。l如果使用MFC AppWizard创建应用程序,向导会根据程序员的要求自动生一个合适的文档模板对象,程序员一般不需要对它进行修改3.8 应用程序类的派生类l3.8.1 应用程序类派生类的代码l作为应用程序,还需要一个应用程序类对象作为上述各类对象的容器,并实现应用程序的初始化和消息循环。l当使用MFC AppWizard生成程序时,向导会自动生成一个CWinApp的派生类。l例如:工程名为My的应用程序类部分代码如下:lClass CMyApp:public CWinAppllpublic:lCMyApp();lpublic:lvirtual BOOL

18、InitInstance();lafx_msg void OnAppAbout();lDECLARE_MESSAGE_MAP()l;lOnAppAbout()是在应用程序用户单击菜单关于项时的消息处理函数。lInitInstance()是需要重写的虚函数l由向导生成的部分InitInstance()代码如下:lBOOL CMyApp:InitInstance()ll .l .l .lCSingleDocTemplate*pDocTemplate;lpDocTemplate=new CSingleDocTemplate(l IDR_MAINFRAME,/文档模板使用的资源IDl RUNTIME_

19、CLASS(CMyDoc),/创建文档对象l RUNTIME_CLASS(CMainFrame),/创建框架l RUNTIME_CLASS(CMyView);/创建视图对象lAddDocTemolate(pDocTemplate);/将文档模板加入模板链表l .l .l .;l当程序启动后,应用程序对象首先创建文档模板,并且在文档模板的构造函数中传递了四个参数:第一个参数是文档模板使用的资源ID,剩下的其余三个参数都是由宏RUNTIME_CLASS()来创建的对象,是由文档模板统一管理的三个内嵌对象3.8.2 程序员的主要工作l如果使用MFC AppWizard创建程序框架,向导会自动提供程序

20、所应有的派生类,并同时定义应用程序类的全局对象和生成主函数。l程序叫的工作主要有如下几个方面:l(1)重写CWinApp派生类的虚函数 l InitInstance(),在此函数中,按自己需l 要创建和显示窗口l(2)在CDoucment的派生类中,声明程序 l 所需要的数据和对这些数据进行必要 l 操作的接口函数l(3)在CView派生类中编写处理消息的代l 码。如果在消息处理过程中需要使用l 程序数据,则由GetDocument()来获l 取文档对象,然后通过接口函数获得l 数据l(4)在CView派生类的OnDraw()函数中编l 写窗口重绘时的代码l(5)用宏实现类的消息映射表3.9

21、MFC 文档/视图应用程序框架中各个对象的关系l文档/视图应用程序框架的构成是比较复杂的,因此,正确理解程序各个部分之间的关系和沟通方法是设计程序的关键l3.9.1 应用程序各对象创建的顺序l应用程序对象是全局对象,它在程序启动之前由系统创建。l应用程序启动之后,程序的主函数先调用应用程序对象的初始化函数InitInstance(),并在该函数中创建文档模板对象。创建单文档模板的对象代码示例lCSingleDocTemplate*pDocTemplate;lpDocTemplate=new CSingleDocTemplate(l IDR_MAINFRAME,l RUNTIME_CLASS(C

22、MyDoc),l RUNTIME_CLASS(CMainFrame),l RUNTIME_CLASS(CMyView);lAddDocTemplate(pDocTemplate);/将文档模板加入链表创建多文档模板的对象代码示例lCMultiDocTemplate*pDocTemplate;lpDocTemplate=new CMultiDocTemplate(l IDR_MYTYPE,l RUNTIME_CLASS(CMyDoc),l RUNTIME_CLASS(CChildFrame),l RUNTIME_CLASS(CMyView);lAddDocTemplate(pDocTemplat

23、e);l/创建多文档主窗口lCMainFrame*pMainFrame=new CMainFrame;lIf(!pMainFrame-LoadFrame(IDR_MAINFRAME)lreturn FALSE;lm_pMainWnd=pMainFrame;l在用文档模板构造函数创建文档模板对象的时候,在文档模板构造函数的参数列表中除了传递所需要的资源ID之外,还用MFC的宏RUNTIME_CLASS()传递了文档类、框架窗口类和视图类的类信息表,然后由模板类的构造函数根据资源和类信息表动态地创建文档、视图、窗口框架三个对象。其中,视图对象是由框架窗口对象创建并管理的。l应用程序不仅要创建文档模

24、板对象,并且将其加入由应用程序对象维护的文档模板链表3.9.2 应用程序各对象之间的联系l1.以文档为中心的结构l一个应用程序只有一应用程序类CWinApp或其派生类的对象。l如果是多文档结构的应用程序,则应用程序必须维护一个文档模板链表对多个文档模板进行管理,应用程序每新建或打开一个文档就会创建一个文档模板并将其加入文档模板链表。l在文档模板中,文档模板委托一个类名为CDocManager的类对象来负责文档对象和窗口框架的管理工作。l每个文档对象都有一个指向其所属文档模板的指针,并且每个文档对象还要管理一个链表,这个链表的每一个节点都指向与该文档相关联的视图对象l框架窗口对象作为视图对象的容

25、器,也有一个由它管理的视图对象链表,并有一个指向当前活动视图对象的指针l视图对象为了能和与之关联的文档对象沟通,每个视图对象都有一个指向与其关联的文档对象的指针,视图对象可以通过调用自己的成员函数GetDocument()获取这个指针,并通过这个指针对文档对象中的数据和函数进行访问或调用l可见,是以文档为中心的结构2.应用程序框架对象之间的联系方法lMFC应用程序框架的各个对象都从各自的基类继承了一些获得其他对象指针的方法,从而可以使各对象通过这些指针与其他对象的成员来互相联系l例如:视图对象可以使用其基类CView的成员函数GetDocTemplate()获得文档模板对象;可以使用GetDo

26、cument()获得与其关联的文档对象;使用GetParentFrame()获得所属的框架窗口对象l框架窗口对象可以使用继承来的GetActiveView()来获得活动视图对象,使用GetActiveDocument()获得活动视图的文档。l文档对象可以使用继承来的GetFirstViewPosition()和GetNextView()获得视图链表中的视图对象l例3-4一个可以在视图对象中显示文档数据成员m_Text和文档标题的应用程序l代码如下:lclass CMFCexp3_4Doc:public CDocumentl.public:lchar*m_Text;l/在文档派生类中定义一个字符

27、指针ll在构造函数中赋初值lCMFCexp3_4Doc:CMFCexp3_4Doc()llm_Text=“Hello!”;ll视图对象的WM_PAINT消息响应函数lvoid CMFCexp3_4View:OnDraw(CDC*pDC)llCMFCexp3_4Doc*pDoc=GetDocument();lpDC-TextOut(50,50,pDoc-m_Text,6);l /显示字符指针的数据lpDC-TextOut(190,50,pDoc-GetTitle();/显示文档标题l3.10 对象的动态创建l3.10.1 问题的提出与解决l虽然由MFC AppWizard自动生成的文档类的派生类

28、是一个通用框架,但一旦用户在类中定义了成员数据和成员函数以后,那么这个文档对象就有了专门用途。l尽管一个文档模板对象可以管理多个文档,但有一条件:这些文档必须是同一类型的。l一个设计完毕的应用程序中的文档模板是有专门用途的。例如,用Word不能打开PS图形文件l但是MFC的MDI程序却希望能打开多种类型的文件,于是MDI程序可以建立多个文档模板。l随之而来的一个问题是,程序启动后,MDI程序应该建立哪种类型的文档模板对象呢?最简单的办法是把程序所有文档模板对象都创建出来,但这不是一个好办法l理想的办法应该是程序向用户提问,当得到答案后,再按要求来创建模板对象l程序应在运行中根据获得的文档类型(

29、文档的扩展名)来建立不同的模板。l于是,MFC就要求应用程序设计人员在程序设计时应该为每个需要动态创建对象的类定义一个可以创建本类对象的创建函数l例如,CMyWnd类的对象创建函数应该:lCObject*CreateObject()lreturn new CMyWnd;ll然后再制作一个全局表,凡是需要动态创建对象的类都在这个表中占一项,把类名称和对象创建函数关联起来,即如图所示那样每项有两个记录:类名称和一个指向CreateObject()函数的指针m_pfnCreateObjectl当程序获得类名后,就可以根据类名在表中找到与其对应的CreateObject()函数指针,并通过指针调用对象

30、构建函数来创建对象l例3-5下面是一个Win32 Console程序,这个程序中的Myclass类是一个带有对象创建函数的类,该程序演示了程序是如何根据从键盘获得的类名来动态创建Myclass类对象的。l该程序首先定义了一个CRuntimeClass来充当上图所示的映射表项,该结构见下面代码相关部分(程序中将这个表项叫类信息表)l然后在Myclass类声明中声明了这个表classMyclass,并在类声明外给它填写了具体表项。l另外,在Myclass类中还声明了对象构建函数CreatObject()和获得类信息表项的方法GetRuntimeClass(),并在类外实现了它们l为了模仿MFC类的

31、继承关系,声明了一个虚函数SayHello()l#include l#includestring.hlclass CObject;/声明一个”空”类,居然行l/类信息表结构如下lstruct CRuntimeClassll char*m_lpszClassName;/类名 l CObject*(_stdcall*m_pfnCreateObject)();/函数指针l CObject*_stdcall CreateObject();l/对象构建函数的声明l;l/CObject类声明及实现lclass CObjectllpublic:virtual void SayHello()cout Hell

32、o CObject n;l;l/派生类Myclass及实现lclass Myclass:public CObjectllpublic:lvirtual void SayHello()cout Hello Myclass n;lpublic:l/动态创建对象声明lstatic CRuntimeClass classMyclass;l/类中定义一信息表结构变量,但是静态的lstatic CRuntimeClass*GetRuntimeClass();l /声明获得类信息表指针的函数l;l/对象构建函数的实现lCObject*_stdcall CreateObject()llreturn new M

33、yclass;ll/填写类信息表lCRuntimeClass Myclass:classMyclass=l Myclass,/类名l CreateObject;l/获得类信息表指针函数的实现lCRuntimeClass*Myclass:GetRuntimeClass()l lreturn&Myclass:classMyclass;l l/主函数lvoid main(void)llchar _lpszCLS10;lcout _lpszCLS;lCRuntimeClass*p=Myclass:GetRuntimeClass();l l if(strcmp(p-m_lpszClassName,_lp

34、szCLS)=0)l l CObject*_stdcall pp=p-m_pfnCreateObject();l pp-SayHello();l l elselcoutNoendl;l l3.10.2 类信息表及其声明和实现lMFC程序在不同的场合下还经常用到其他信息,于是MFC就把这些信息统统都放到上面所说的映射表项中,并反它叫做类信息表。l在MFC中,一个类的信息表是一个CRuntimeClass结构变量,该结构与对象动态创建及表结构有关成员列举如下:lStruct CRuntimeClassll LPCSTR m_lpszClassName;/类名称l CObject*l (PASCAL

35、*m_pfnCreateObject)();l /动态创建对象的函数指针l CObject*_stdcall CreateObject();l /创建函数的原型声明l CRuntimeClass*m_pBaseClass;l CRuntimeClass*m_pNextClass;ll由结构的最后两个域可以知道,MFC在这里再次使用链表结构,把各个类的类信息表组成了一个总表。l与处理消息映射表的方法类似lMFC用宏DECLARE_DYNCREATE封装了类信息表的声明代码lMFC用宏IMPLEMENT_DYNCREATE封装了类信息表及其链表的实现代码。l在设计具有动态创建对象能力的类时,必须要在类中使用这两个宏动态创建对象_宏使用示例lClass A:public Bll public:l DECLARE_DYNCREATE(A)l /类中声明本类的类信息表结构l;lIMPLEMENT_DYNCREATE(A,B)l/类外填写类信息表3.10.3 对象类信息表的提取l为了使程序在运行时能根据类名提到类信息链表中获得该类的信息表,MFC使用宏来获得一个指向类信息表的指针,例:l RUNTIME_CLASS(class_name)l在前面文档模板的构造函数中已经看到这个宏的应用

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁