简单MFC应用程序开发.ppt
第第1111章章 简单简单MFCMFC应用程序开发应用程序开发l重点重点 1.SDI 1.SDI中文档中文档/视图应用程序视图应用程序 2.2.对话框应用程序对话框应用程序 3.3.示例系统中客户端界面设计示例系统中客户端界面设计2009年1月1重庆理工大学计算机科学与技术系11.1.1 11.1.1 单文档与多文档界面单文档与多文档界面11.1 11.1 文档文档/视图概述视图概述SDISDI应用程序只支持打开一个文档,如应用程序只支持打开一个文档,如WindowsWindows中的记事本是中的记事本是SDISDI应用程序的一个典型例子。应用程序的一个典型例子。MDIMDI应用程序每次可以读写多应用程序每次可以读写多个文件或文档,可以同时有多个子窗口,对多个文档进行操个文件或文档,可以同时有多个子窗口,对多个文档进行操作,如作,如WordWord程序。程序。2009年1月2重庆理工大学计算机科学与技术系11.1.2 11.1.2 文档文档/视图结构视图结构一个典型一个典型SDISDI文档文档/视图应用程序主要包括视图应用程序主要包括4 4个部分:应用程个部分:应用程序对象、框架窗口对象、视图对象和文档对象。序对象、框架窗口对象、视图对象和文档对象。应用程序对象:从应用程序对象:从CWinAppCWinApp派生,管理应用程序的初始化,负责保持派生,管理应用程序的初始化,负责保持文档、视图、框架窗口类之间的关系,接收文档、视图、框架窗口类之间的关系,接收WindowsWindows消息,将消息调消息,将消息调度到需要的目标窗口;度到需要的目标窗口;框架窗口对象:提供了一个应用程序的主窗口,通常窗口包含一个框架窗口对象:提供了一个应用程序的主窗口,通常窗口包含一个最大最大/最小化按钮、标题栏和系统菜单。它还可以用来处理工具条和最小化按钮、标题栏和系统菜单。它还可以用来处理工具条和状态条的创建、初始化和销毁;状态条的创建、初始化和销毁;文档对象:负责对数据进行管理和维护,数据通常被保存在文档类文档对象:负责对数据进行管理和维护,数据通常被保存在文档类的成员变量中;的成员变量中;视图对象:文档和用户之间的中介。视图可以直接或间接地访问文视图对象:文档和用户之间的中介。视图可以直接或间接地访问文档类中的成员变量,它从文档类中将数据读出来,然后在屏幕上显档类中的成员变量,它从文档类中将数据读出来,然后在屏幕上显示。每个文档可以有多个视图,但每个视图只能对应于一个确定的示。每个文档可以有多个视图,但每个视图只能对应于一个确定的文档。文档。对于多文档应用程序,文档对于多文档应用程序,文档/视图结构和视图结构和SDISDI程序几乎相同,程序几乎相同,只是具有多个文档对象和视图对象。只是具有多个文档对象和视图对象。2009年1月3重庆理工大学计算机科学与技术系11.1.3 SDI11.1.3 SDI程序中文档程序中文档/视图对象的创建过程视图对象的创建过程系统首先创建了一个单文档模板类,该类主要用来将程序中系统首先创建了一个单文档模板类,该类主要用来将程序中的文档类、视图类和框架窗口类联系在一起进行管理;的文档类、视图类和框架窗口类联系在一起进行管理;构造函数的参数中含有资源的构造函数的参数中含有资源的IDID,文档、框架窗口、视图的,文档、框架窗口、视图的类名和类名和RUNTIME_CLASSRUNTIME_CLASS宏;宏;RUNTIME_CLASSRUNTIME_CLASS宏对于所指定的类返回指向宏对于所指定的类返回指向CRuntimeClassCRuntimeClass的的指针,使得主结构可以在运行时动态创建这些类的对象;指针,使得主结构可以在运行时动态创建这些类的对象;对于多对于多文档应用程序,定义的文档模板对象是文档应用程序,定义的文档模板对象是CMultiDocTemplateCMultiDocTemplate类的对象。类的对象。/注册应用程序的文档模板。文档模板将用作文档、框架窗口和视图之间的连接注册应用程序的文档模板。文档模板将用作文档、框架窗口和视图之间的连接CSingleDocTemplate*pDocTemplate;pDocTemplate=new CSingleDocTemplate(/创建单文档模板类对象创建单文档模板类对象IDR_MAINFRAME,/应用程序中各种资源应用程序中各种资源IDRUNTIME_CLASS(CTestDoc),/CTestDoc是应用程序中的文档类是应用程序中的文档类RUNTIME_CLASS(CMainFrame),/CMainFrame是应用程序的框架窗口类是应用程序的框架窗口类RUNTIME_CLASS(CTestView);/CTestView是应用程序的视图类是应用程序的视图类2009年1月4重庆理工大学计算机科学与技术系11.1.4 11.1.4 文档文档/视图结构程序的消息传递过程视图结构程序的消息传递过程文档、视图和框架窗口被创建后,消息循环就开始工作了;文档、视图和框架窗口被创建后,消息循环就开始工作了;某种类型的消息按照特定的顺序从一个对象传到另一个对象,某种类型的消息按照特定的顺序从一个对象传到另一个对象,直到该消息被某个消息处理函数处理,否则将消息传递到直到该消息被某个消息处理函数处理,否则将消息传递到DefWindowProcDefWindowProc函数进行默认处理;函数进行默认处理;当用户选择菜单项、按快捷键或单击工具条按钮时,系统会当用户选择菜单项、按快捷键或单击工具条按钮时,系统会发送发送WM_COMMANDWM_COMMAND消息。消息。WM_COMMANDWM_COMMAND消息首先发送给活动的视消息首先发送给活动的视图,其次发送给该视图相对应的文档和文档模板对象,再传图,其次发送给该视图相对应的文档和文档模板对象,再传送到框架窗口和应用程序对象。最后调用送到框架窗口和应用程序对象。最后调用DefWindowProcDefWindowProc函函数采用默认处理。只要在传递过程中有一个对象接收并处理数采用默认处理。只要在传递过程中有一个对象接收并处理了此消息,那么后面的对象都接收不到该消息;了此消息,那么后面的对象都接收不到该消息;只有只有WM_COMMANDWM_COMMAND消息和用户界面更新消息才遵循上面的消息消息和用户界面更新消息才遵循上面的消息传递机制,对于标准的传递机制,对于标准的WindowsWindows消息,如鼠标和键盘消息通消息,如鼠标和键盘消息通常传递给视图,大多数其他的消息则传递到框架窗口;常传递给视图,大多数其他的消息则传递到框架窗口;文档对象和应用程序对象从不接收非命令消息。文档对象和应用程序对象从不接收非命令消息。2009年1月5重庆理工大学计算机科学与技术系11.2.1 CWinApp11.2.1 CWinApp类类11.2 11.2 文档文档/视图结构程序的主要成员视图结构程序的主要成员CWinAppCWinApp类代表主程序,类代表主程序,CWinAppCWinApp本身是不可见的,应用程序本身是不可见的,应用程序通过从通过从CWinAppCWinApp继承来的应用程序类来实现相关的功能,它继承来的应用程序类来实现相关的功能,它负责维护程序进程的启动、终止、消息循环、命令行参数、负责维护程序进程的启动、终止、消息循环、命令行参数、资源管理等;资源管理等;CWinAppCWinApp类中类中InitInstanceInitInstance与与ExitInstanceExitInstance是最常见的被重是最常见的被重载的两个成员函数。载的两个成员函数。文档文档/视图结构程序的核心类有视图结构程序的核心类有5 5个:个:CWinAppCWinApp、CDocumentCDocument、CViewCView、CDocTemplateCDocTemplate和和CFrameWndCFrameWnd。2009年1月6重庆理工大学计算机科学与技术系11.2.2 CDocument11.2.2 CDocument类类所有文档类都以所有文档类都以CDocumentCDocument类为基类;类为基类;CDocumentCDocument提供的一般成员函数和虚拟成员函数参见教材提供的一般成员函数和虚拟成员函数参见教材P P233233表表11-111-1和教和教材材P P234234表表11-211-2;CDocumentCDocument提供的成员函数中最常用的是提供的成员函数中最常用的是SetModifiedFlag()SetModifiedFlag()和和UpdateAllViewsUpdateAllViews()();文档内容被修改之后,一般要调用文档内容被修改之后,一般要调用SetModifiedFlag()SetModifiedFlag()来设定一个标志,在来设定一个标志,在MFCMFC关闭文档之前提示用户保存该数据;关闭文档之前提示用户保存该数据;UpdateAllViews()UpdateAllViews()刷新所有和文档关联的视图,实际上该函数调用各个视图刷新所有和文档关联的视图,实际上该函数调用各个视图类的类的OnUpdate()OnUpdate()函数,以保证各个视图之间的同步。函数,以保证各个视图之间的同步。可以通过使用函数可以通过使用函数GetFirstViewPosition()GetFirstViewPosition()和和GetNextView()GetNextView()得到和文得到和文档关联的视图的指针,从而进一步和视图联系,通常代码形式如下:档关联的视图的指针,从而进一步和视图联系,通常代码形式如下:从从CDocumentCDocument类派生新的文档类的一般过程如下:类派生新的文档类的一般过程如下:为每一个文档类型从为每一个文档类型从CDocumentCDocument类派生一个相应的文档类;类派生一个相应的文档类;添加用来存储文档数据的成员变量;添加用来存储文档数据的成员变量;重载重载SerializeSerialize成员函数,实现文档数据的串行化;成员函数,实现文档数据的串行化;POSITION pos=GetFirstViewPosition();While(pos!=NULL)CView*pView=GetNextView(pos);.2009年1月7重庆理工大学计算机科学与技术系11.2.3 CView11.2.3 CView类类CViewCView类从类从CWndCWnd派生出来,它提供的一般成员函数和虚拟成员函数参见派生出来,它提供的一般成员函数和虚拟成员函数参见教材教材P P235235表表11-311-3和教材和教材P P235235表表11-411-4;一个视图类可以通过一个视图类可以通过GetDocument()GetDocument()函数得到和它关联的文档的指针,函数得到和它关联的文档的指针,进一步可以得到文档中保存的数据;进一步可以得到文档中保存的数据;当一个文档对象的数据发生变化时,该文档对象可以通过调用成员函数当一个文档对象的数据发生变化时,该文档对象可以通过调用成员函数UpdateAllViewsUpdateAllViews()()来刷新所有的视图;来刷新所有的视图;CViewCView类中最常用的是类中最常用的是OnDraw()OnDraw()函数,该函数在屏幕发生变化或因为焦函数,该函数在屏幕发生变化或因为焦点的变化需要重绘时调用,没有该函数,就不可能在程序切换时保证屏点的变化需要重绘时调用,没有该函数,就不可能在程序切换时保证屏幕的正确显示;幕的正确显示;OnDrawOnDraw和和WM_PAINTWM_PAINT消息不同:消息不同:只要需要重绘都会调用只要需要重绘都会调用OnDrawOnDraw,无论是往屏幕上绘制还是往打印机打印;,无论是往屏幕上绘制还是往打印机打印;WM_PAINTWM_PAINT只负责往屏幕上绘制,只负责往屏幕上绘制,WM_PRINTWM_PRINT消息负责往打印机打印;消息负责往打印机打印;尽量不要在尽量不要在OnDrawOnDraw之外的函数中调用绘图方法,因为那些方法不会在视之外的函数中调用绘图方法,因为那些方法不会在视图需要重绘时被自动调用;图需要重绘时被自动调用;调用调用InvalidateInvalidate和和UpdateWindowUpdateWindow成员函数可以强制视图重绘。但是不要成员函数可以强制视图重绘。但是不要在在OnDrawOnDraw中调用这两个成员函数,否则会引起递归循环调用,导致程序中调用这两个成员函数,否则会引起递归循环调用,导致程序陷入死循环;陷入死循环;OnUpdateOnUpdate函数会在每次视图数据更新的时候被调用。函数会在每次视图数据更新的时候被调用。2009年1月8重庆理工大学计算机科学与技术系11.2.4 CDocTemplate11.2.4 CDocTemplate类类CDocTemplateCDocTemplate类在文档类在文档/视图结构中将原本独立的文档、视图和框架窗视图结构中将原本独立的文档、视图和框架窗口对象联系在一起;口对象联系在一起;CDocTemplateCDocTemplate提供的一般成员函数和虚拟成员函数参见教材提供的一般成员函数和虚拟成员函数参见教材P P236236表表11-511-5在单文档在单文档SDISDI应用程序中只有一个文档模板对象,而应用程序中只有一个文档模板对象,而MDIMDI应用程序需要针应用程序需要针对不同类型的文档定义不同的文档模板对象;对不同类型的文档定义不同的文档模板对象;在在Doc/ViewDoc/View结构中,假设某个视图想要获得文档,或某个框架需要获得结构中,假设某个视图想要获得文档,或某个框架需要获得活动视图,可以通过下表中提供的成员函数解决:活动视图,可以通过下表中提供的成员函数解决:当前位置当前位置被访问位置被访问位置访问成员函数访问成员函数文档文档视图视图GetFirstViewPosition()GetFirstViewPosition()和和GetNextView()GetNextView()文档文档模板模板GetDocTemplate()GetDocTemplate()视图视图文档文档GetDocument()GetDocument()视图视图框架框架GetParentFrame()GetParentFrame()框架框架视图视图GetActiveView()GetActiveView()框架框架文档文档GetActiveDocument()GetActiveDocument()MDIMDI主框架主框架MDIMDI子框架子框架MDIGetActive()MDIGetActive()MDIMDI子框架子框架MDIMDI主框架主框架GetParentFrame()GetParentFrame()任何位置任何位置应用程序应用程序AfxGetApp()AfxGetApp()任何位置任何位置主框架主框架AfxGetMainWnd()AfxGetMainWnd()2009年1月9重庆理工大学计算机科学与技术系11.2.5 CFrameWnd11.2.5 CFrameWnd类类CFrameWndCFrameWnd对象负责工对象负责工具条、菜单、状态条的显示、更新,具条、菜单、状态条的显示、更新,视图的位置和显示,其他可停靠控件的停靠和动态尺寸调整视图的位置和显示,其他可停靠控件的停靠和动态尺寸调整等。等。11.2.6 11.2.6 串行化处理串行化处理MFCMFC中使用串行化这个概念来描述将对象写入字节流和从字中使用串行化这个概念来描述将对象写入字节流和从字节流恢复对象的操作;节流恢复对象的操作;之所以使用字节流而不是使用文件,是因为串行化除了可以之所以使用字节流而不是使用文件,是因为串行化除了可以使用文件保存对象之外,还可以通过网络、串口来传输对象;使用文件保存对象之外,还可以通过网络、串口来传输对象;使用串行化的好处是不需要重载文件打开、文件保存等成员使用串行化的好处是不需要重载文件打开、文件保存等成员函数,函数,MFCMFC的文档的文档/视图框架会自动完成这些任务,并自动调视图框架会自动完成这些任务,并自动调用文档类的用文档类的SerializeSerialize函数来完成串行化过程;函数来完成串行化过程;如果不使用如果不使用MFCMFC提供的串行化框架,就需要重载一些函数来提供的串行化框架,就需要重载一些函数来获取文件名,然后自己读获取文件名,然后自己读/写文件完成对象的串行化;写文件完成对象的串行化;2009年1月10重庆理工大学计算机科学与技术系11.3 SDI11.3 SDI编程实例编程实例参见例题参见例题11-111-1。2009年1月11重庆理工大学计算机科学与技术系11.4 11.4 对话框应用程序设计对话框应用程序设计一个对话框由两部分组成:一个对话框由两部分组成:对话框模板资源:用于指定对话框的控件及其布局;对话框模板资源:用于指定对话框的控件及其布局;对话框类:用来实现对话框的功能,一般是从对话框类:用来实现对话框的功能,一般是从CDialogCDialog类派生而来;类派生而来;控件实际上都是窗口,所有的控件类都是控件实际上都是窗口,所有的控件类都是CWndCWnd类的派生类。类的派生类。控件通常是作为对话框的子窗口而创建的,控件也可以出现控件通常是作为对话框的子窗口而创建的,控件也可以出现在窗口、工具条和状态条中。在窗口、工具条和状态条中。11.4.1 11.4.1 对话框和控件的基本概念对话框和控件的基本概念11.4.2 11.4.2 对话框模板的设计对话框模板的设计完成示例系统中客户端登录对话框的设计,参见实验。完成示例系统中客户端登录对话框的设计,参见实验。2009年1月12重庆理工大学计算机科学与技术系11.4.3 11.4.3 对话框类的设计对话框类的设计完成示例系统中客户端登录对话框类的创建,为该对话框类完成示例系统中客户端登录对话框类的创建,为该对话框类加入成员变量,并在对话框初始化函数中完成初始化工作;加入成员变量,并在对话框初始化函数中完成初始化工作;对话框的数据交换机制对话框的数据交换机制对话框的数据成员变量用来存储与控件相对应的数据,数据变量需对话框的数据成员变量用来存储与控件相对应的数据,数据变量需要和控件交换数据,以完成输入或输出功能;要和控件交换数据,以完成输入或输出功能;MFCMFC提供了类提供了类CDataExchangeCDataExchange来实现对话框类与控件之间的数据交换来实现对话框类与控件之间的数据交换(DDX)(DDX)和数据有效机制和数据有效机制(DDV)(DDV);数据交换的工作由数据交换的工作由CDialog:DoDataExchangeCDialog:DoDataExchange成员函数来完成,但是成员函数来完成,但是程序员不直接调用该函数,而是程序员不直接调用该函数,而是CWnd:UpdateDataCWnd:UpdateData函数。函数。2009年1月13重庆理工大学计算机科学与技术系11.4.3 11.4.3 对话框类的设计(续)对话框类的设计(续)对话框的运行机制:在对话框的运行机制:在MFCMFC程序中运行模态对话框分为两个步骤:程序中运行模态对话框分为两个步骤:构建一个对话框类对象;构建一个对话框类对象;利用该对象调用利用该对象调用CDialog:DoModal()CDialog:DoModal():DoModalDoModal函数负责模态对话框函数负责模态对话框的创建和撤销。在创建对话框时,的创建和撤销。在创建对话框时,DoModalDoModal的任务包括载入对话框模的任务包括载入对话框模板资源,调用板资源,调用OnInitDialogOnInitDialog初始化对话框,将对话框显示在屏幕上。初始化对话框,将对话框显示在屏幕上。完成对话框的创建后,完成对话框的创建后,DoModalDoModal启动一个消息循环,以响应用户的输启动一个消息循环,以响应用户的输入。由于该消息循环截获了几乎所有的输入消息,使主消息循环收入。由于该消息循环截获了几乎所有的输入消息,使主消息循环收不到其他消息的输入,致使用户只能与模态对话框进行交互,而其不到其他消息的输入,致使用户只能与模态对话框进行交互,而其他用户界面对象收不到输入信息;他用户界面对象收不到输入信息;若用户在对话框内单击了若用户在对话框内单击了IDID为为IDOKIDOK的按钮的按钮(通常该按钮的标题是通常该按钮的标题是“确确定定”或或OK)OK),或按了回车键,则,或按了回车键,则CDialog:OnOKCDialog:OnOK将被调用。将被调用。OnOKOnOK首先首先调用调用UpdateData(TRUE)UpdateData(TRUE)将数据从控件传给对话框成员变量,然后调将数据从控件传给对话框成员变量,然后调用用CDialog:EndDialogCDialog:EndDialog关闭对话框。关闭对话框后,关闭对话框。关闭对话框后,DoModalDoModal会返回会返回值值IDOKIDOK;若用户单击了若用户单击了IDID为为IDCANCELIDCANCEL的按钮的按钮(通常其标题为通常其标题为“取消取消”或或Cancel)Cancel),或按了,或按了EscEsc键,则会调用键,则会调用CDialog:OnCancelCDialog:OnCancel。该函数只调。该函数只调用用CDialog:EndDialogCDialog:EndDialog关闭对话框。关闭对话框后,关闭对话框。关闭对话框后,DoModalDoModal会返回会返回值值IDCANCELIDCANCEL。2009年1月14重庆理工大学计算机科学与技术系