MFC应用程序概述 (2).ppt
第3章 MFC应用程序概述,MFC应用程序概述,Windows 应用程序概述MFC应用程序框架文档/视图结构消息映射,3.1 Windows 应用程序概述,3.1.1 窗口编程基础窗口消息和消息队列事件驱动的程序设计资源管理,1.窗口(Window),窗口是应用程序与用户交互的界面窗口元素以对象方式组织一个应用程序由多个窗口组成程序运行过程是窗口之间,窗口与系统,窗口与用户之间交换并处理数据的过程。,2.窗口的界面元素,消息(Message)和消息队列,消息用于通知某个事件的产生消息机制MSG消息的类型,消息(Message)和消息队列,Windows应用程序是利用消息与其他Windows应用程序和操作系统进行信息交换的。消息的作用是通知一个应用程序某个确定的事件的产生。应用程序对该事件做出响应,即编写相应的消息处理代码。举例:按下鼠标左键时,系统会产生WM_LBUTTONDOWN消息,消息(Message)和消息队列,Windows应用程序接受系统队列传递过来的消息的步骤:(1)每个Windows应用程序都有一个WinMain()函数,在该函数中会定义一个窗口句柄,当应用程序启动时,会使该窗口句柄注册,操作系统使用窗口句柄与Windows应用程序通信。,消息(Message)和消息队列,(2)Windows应用程序创建一个或多个窗口,每个窗口都有一个窗口处理函数(WndProc),负责窗口显示和响应用户输入。(3)消息映射(Message Mapping):负责从消息队列中取消息,并送回窗口,由窗口处理函数选择合适的消息处理函数响应消息。,派送消息,消息源1,消息源2,消息源n,否,捕获消息,处理消息,是否退出消息,是,消息机制,消息机制是Windows应用程序运行的核心工作机制,用如下结构体MSG表示:typedef struct tagMSG HWND hwnd;UINT message;WPARAM wParam;LPARAM lParam;DWORD time;POINT pt;MSG;,MSG结构体成员说明:(1)hwnd 接收消息的窗口句柄。(2)Message 消息值,每个windows消息都有一个消息值,该值由windows.h头文件的宏定义来标识。,(3)wParam和lParam 包含有关消息的附加信息,它随消息的不同而不同。(4)Time 指定消息送至队列的时间界限。(5)pt 指定消息发送时屏幕光标的位置,结构如下:typedef struct tagPOINT LONG x;LONG y;POINT;,消息的类型,1.输入消息 由键盘和鼠标操作产生输入消息。这类消息首先放在系统消息队列中,后由Windows操作系统将他们放到应用程序消息队列中,由应用程序处理消息。2.控件消息 用户操作窗口对象时产生控件消息,这类消息一般不进入应用程序消息队列,而直接发送到控件对象所属的对话框窗口,消息的类型,3.系统消息 对程序化的事件或系统时钟中断做出的放映。一类例如DDE(动态数据交换消息)要通过Windows的系统消息队列,送入应用程序的消息队列,另一类直接送入应用程序的消息队列,例如创建窗口消息。4.用户消息 是程序员自己定义并在应用程序中主动发出的,一般由应用程序的某一部分做内部处理。,3.事件驱动的程序设计,Windows操作系统下的Windows应用程序采用事件驱动的程序设计,与Dos操作系统下面向过程有明显不同。事件驱动的程序的逻辑顺序是按事件的产生而决定的。事件的产生不是预先定义的,有着随机性。,3.事件驱动的程序设计,例1、一个应用程序的功能是体操全能比赛项目运动成绩管理,体操全能包括4个项目,在一个驱动中需要如下步骤:(1)输入第一项运动员的成绩。(2)输入第二项运动员的成绩。(3)输入第三项运动员的成绩。(4)输入第四项运动员的成绩。(5)计算每个运动员的总分。(6)按总分排名。,事件驱动程序流程示例,4.资源管理,资源的类型用户自定义资源菜单对话框工具栏系统资源设备上下文画刷画笔字体通信端口,3.1.2 Windows应用程序组成,一个应用程序是如何开始?操作系统创建一个新的进程和一个初始线程应用程序代码装载到内存动态链接库装载到内存(如果需要使用DLL)为数据和堆栈分配物理内存,并映射到虚拟内存应用程序开始执行,3.1.2 Windows应用程序组成,Windows应用程序必须包含两个基本函数:(1)应用程序主函数WinMain()WinMain函数定义了窗口句柄,创建初始化窗口并启动一个消息循环。(2)窗口处理函数WinProc()WinProc函数处理所有从操作系统传递到窗口的消息。每一个窗口都要有一个窗口处理函数。,3.1.2 Windows应用程序组成,1.WinMain()函数 Windows应用程序是从WinMain()函数开始和结束的。在”WINBASE.H”中定义如下:int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSR lpCmdLine,int nCmdShow);,3.1.2 Windows应用程序组成,参数说明如下:(1)hInstance 系统分配的窗口所属的应用程序的实例句柄,标识当前进程的实例,是进程所占据的地址空间的首地址,是程序的唯一标识。(2)hPrevInstance 用于检查是否有多个程序实例运行。,3.1.2 Windows应用程序组成,(3)lpCmdLine 是一个指向字符串的指针,用来保存程序运行时的参数,同main函数中的argv 相似。(4)nCmdShow 用来指明应用程序的主窗口的显示方式(最大化,最小化,一般显示),通常被ShowWindow()函数作为显示窗口的参数。,3.1.2 Windows应用程序组成,WinMain函数的作用:注册窗口类,创建并初始化窗口,创建消息循环(message loop)。(1)注册窗口类 每个窗口都包含一些基本属性,如窗口边框、标题、大小、位置、鼠标、背景色等,注册的过程是将这些属性报告给系统。,3.1.2 Windows应用程序组成,(2)创建并初始化窗口 CreateWindow()函数用于创建窗口,定义了窗口的名称、位置、尺寸等数据,创建成功返回窗口句柄,否则为0。创建后创口需要调用ShowWindow()和UpdateWindow()两个函数显示窗口。,3.1.2 Windows应用程序组成,(3)创建消息循环 使用While语句创建一个消息循环,负责从消息队列中获取消息并发送给相应的处理函数。while(GetMessage(TranslateMessage()函数的作用是将来自键盘的命令翻译为消息的ID字符表示。DispatchMessage()把每个消息分发给相应的窗口函数。,3.1.2 Windows应用程序组成,2.窗口处理函数 决定窗口在它的客户区中显示哪些内容、窗口如何响应用户输入,窗口函数定义如下:LRESULT CALLBACK WndProc(HWND hwnd,UNIT Message,WPARAM wParam,LPARAM lparam,),3.1.2 Windows应用程序组成,参数说明如下:(1)LRESULT 表示该函数返回值为长整数,由系统使用。(2)CALLBACK 表示该函数是回调函数,由系统使用。(3)Hwnd 接收消息的窗口句柄(4)Message用来标示消息的数字(5)wParam和lparam两个32位的消息参数,用来提供消息的附加信息。,Windows的编程模型与MS-DOS编程模型之比较,第一,用C语言编写基于MS-DOS的应用程序时,唯一绝对需要的是一个名为main的函数。而当Windows操作系统启动一个程序时,调用的是WinMain函数。第二,许多MS-DOS程序直接写显存和打印机接口。这种技术的不利之处是对每一种设备需要其支持的驱动程序软件。Windows引入了一个名为图形设备接口(GDI)的抽象化外层,所以用户不必知道有关系统设备的类型。Windows程序不是寻址硬件,而是调用GDI函数。,Windows的编程模型与MS-DOS编程模型之比较,第三,要在MS-DOS环境下进行数据驱动编程,必须或者为把数据编码成为初始化常量或者提供独立的数据文件让程序来读。进行Windows编程时,使用大量已经确立的格式在资源文件中存储数据。第四,在MS-DOS环境下一个程序的所有对象模块在建立过程中是静态连接的。Windows允许动态链接,这意味着特别创建的库可以在运行时加载和链接。多个应用程序可以共享动态链接库(DLLs),它节省内存和磁盘空间。动态链接增加了程序的模块性。,3.1.3 应用程序举例,分析使用AppWizard生成的Win32窗口程序示例Exam3_2,并对该程序作以下修改:(1)修改输出的文本字符串”Hello World”为”Hello C+!”。(2)在视图的中央输出文本”Starting your VC+learning!”(3)添加一个对话框,并能使用菜单调用这个对话框。,3.2 MFC应用程序框架,Visual C+6.0是一种集成开发环境,提供了MFC类库。MFC(Microsoft基本类库,Microsoft Foundation Class Library)MFC是微软公司对大部分标准的Win32 API函数的封装,提供了图形环境应用程序的框架及创建应用程序的组件.,MFC 简 介,MFC是用来写Windows应用程序的VC+类集,该类集以层次结构组织起来。提供的类库对程序设计高度抽象,使代码的可靠性和重用性得到很大的提高。MFC给Windows系统开发平台程序员以最好支持的基本类结构,它包含的类分层结构和功能是具有可伸缩性,在功能扩展的同时,MFC还保持了程序的向下兼容性。,MFC类的层次结构,MFC类库中是以层次结构的方式组织起来的,每个层次结构都与一具体的Windows的实体相对应。大多数MFC类是从3个基类(CObject类、CCmdTarget类、CWnd类)派生的,MFC类的层次结构,根类:CObject类CObject类 CCmdTarget类CWnd类从CObject类派生的类具有运行时获得对象大小的名字的能力从CCmdTarget类派生的类能够处理命令消息从CWnd类派生的类能够控制窗口,派生,派生,CObject派生类,MFC类的层次结构,MFC提供的一些重要的类分为以下几种:应用程序框架结构类CWinApp程序窗口类CFramWnd图形打印类CGdiObject文件类CFileInternet类集合类异常和调试支持类,应用程序类CWinApp,应用程序框架类主要包括应用程序类、线程类、文档类和文档模板类。应用程序类CWinApp:每个MFC应用程序只能由一个CWinApp的派生对象。CWinApp是应用程序开始后创建的第一个对象,结束前最后一个执行对象。,文档类CDocument,文档类Cdocument封装了应用程序的数据管理功能,可以存储和载入用户定义的持久数据提供“容器”文档类负责将一个文档赋给它的成员变量,并允许视图类编辑这些成员变量。,程序窗口类CWnd,程序窗口类主要包括框架窗口类、对话框类、视图类、控件类等。类CWnd提供了MFC中所有窗口类的基本功能,作为所有类的公共基类。创建一个Windows窗口需二步,首先引入构造函数,构造一个CWnd对象,然后调用Create建立Windows窗口并将它连接到CWnd对象上。,框架窗口类CFramWnd,框架窗口类CFramWnd是CWnd类的子类,创建和维护窗口的边框、菜单栏、工具栏、状态栏等部分.一个SDI应用程序,主框架类是从CMainFrame派生的,对于一个MDI应用程序,主框架类是从CMDIFramWnd派生的。,视图类CView,视图类是应用程序中较重要的类,应用程序返回的结果大多在视图类上进行进行和显示,CView 是用于让用户通过窗口来访问文档,提供人机交互的界面。视图类负责描述文档的内容,也可以用户编辑文档。创建应用程序时,创建文档类的一个实例后将创建视图类Cview的一个实例。,几种视图类,CView类是基本视类,支持基本操作CScrollView类提供了滚动功能,设置滚动尺寸和坐标模式。CFormView类可在资源文件中定义界面的能力,并可将子窗口和变量进行绑定。CListView类利用ListCtrl(列表框)界面作为视界面CEditView类利用Edit接收用户输入,具有输入框的一切功能,可实现多行文本的编辑。,对话框类CDialog,CDialog类封装了用来创建对话框的Windows API,在创建时可以用对话框模板中定义的控件来填充。CDialog 可分别处理无模式和有模式两种类型的对话框.几个MFC通用对话框类CColorDialog、CFileDialog、CFontDialog、CPrintDialog。,控件类和控制栏类,常用控件类CButton类,CListCtrl类,CProgressCtrl类,CTreeCtrl类,CComboBox类,CEdit类等。控制栏类(CControl类的派生类),从编成的角度看,工具栏只是CToolBar类的一个对象,状态栏是CStatusBar类的对象。,MFC应用程序框架分析,在一个CHello SDI应用程序中,向导为我们生成了4个主要的类,这些类都是MFC类的派生类,分别包含在对应的头文件以及实现文件中。分析每个类的作用,MFC应用程序框架分析,CHelloApp类类CHelloApp的一个对象代表一个应用程序。程序定义了一个全局CHelloApp对象theApp。CWinApp基类决定theApp的大多数行为。CWinApp类重载函数:InitInstance(),完成应用的初始化以,与WinMain函数结构中的初始化处理相对应。,MFC应用程序框架分析,典型的一个应用程序将有一个主应用程序窗口。因此,CHelloApp 应用程序类定义了一个名为 m_pMainWnd 成员变量来指向主窗口。InitInstance 函数建立了一个 CHelloWindow 事例,并使用 m_pMainWnd 来指向一个新的窗口,MFC应用程序框架分析,CMainFrame代表的是程序的主框架窗口。框架窗口类及其相关的文件框架窗口类对应应用程序的主窗口,他的定义是在头文件MainFrm.h中,而实现则是在MainFrm.cpp文件中。所有与框架窗口相关的功能都是在这里定义和实现的。,MFC应用程序框架分析,文档类及其相关的文件 文档类在应用程序中没有直观的对应关系,但这一点就是MFC的框架的一个特点就是文档/视图结构。可以抽象一点地来理解,比如说我们在Word中打开了一个文件,其实,这个文件就是文档,而我们看到的只不过是这个文件一个视图,所以说文档提供了应用程序显示的支持,但是我们真正看到的应用程序显示的则是一个视图,文档类的定义是在“CHelloDoc.h”中,而他的实现则是在“CHello Doc.cpp”文件中。,MFC应用程序框架分析,视图类及其相关的文件 视图类是用来显示文档对象的内容的,我们在Word程序中所看到的界面就是一个视图,我们要修改,画图首先操作的对象就是视图,所以,视图类就如他的名称所指出的那样,提供了从用户角度看到的东西。视图类的定义在“CHelloView.h”中,实现是在文件“CHelloView.h”中。,MFC应用程序框架分析,应用程序类及其相关的文件 MFC应用程序的初始化,启动运行和结束都是由应用程序对象完成的。他对应的文件是”Hello World.cpp”和”Hello World.h”。,MFC应用程序框架分析,大致的看出MFC应用程序对象之间的关系了。应用程序一开始生成应用程序对象,然后,在InitInstance中创建中将会创建文档模板对象,应用程序就可以通过建立的模板对象来管理文档、视图、和框架窗口。,3.3 消息映射,在Win32的窗口函数中,采用switch_case结构进行消息处理,在MFC中通过消息映射的方法,将消息映射到各个处理函数。本节内容包括:消息的类别及描述消息映射系统消息处理的路径自定义消息处理,3.3.1 消息的类别,MSG结构描述消息,区别消息一般是对结构中的主消息message、附加参数wParam和lParam3个字段进行判断在MFC中,消息分为窗口消息,命令消息和控件消息三种类型。,窗口消息的描述,1.窗口消息 只能被窗口或者窗口对象处理,在MFC中油CView和CFrame及其派生类、及自定义窗口类处理窗口消息。描述:message:WM_XXX wParam和 lParam:随WM_XXX而变 举例:WM_LBUTTONDOWN鼠标左键消息,wParam是一个整数值,标识鼠标按下是哪个键,lParam的低字节是鼠标的X坐标,高字节是鼠标的Y坐标。,命令消息的描述,2.命令消息 选择菜单项、单击工具栏按钮等都可以产生命令消息,从基类CCmdTarget派生的类都能处理命令消息 描述:message:WM_COMMAND wParam:低16位为命令ID、高16位为0lParam:0L,控件消息的描述,3.控件消息 当控件事件发生时,如改变文本框控件的内容、选择列表框控件中某一选项产生控件消息,由控件所属的对话框类处理描述:message:WM_NOTIFY wParam:控件ID lParam:指向NMHDR的指针,NMHDR是包含了消息内容的一个结构,消息宏前缀,3.3.2 消息映射系统,MFC消息映射由两大块组成:1.CCmdTarget的派生类每个子类都能接收和处理消息,并定义了一个消息映射表2.消息映射。MFC提供了3个宏管理消息映射。DECLARE_MESSAGE_MAP()BEGIN_MESSAGE_MAP()END_MESSAGE_MAP(),MFC消息映射原理,应用程序开始运行后有一个从CWinApp派生的对象,等待和处理消息的函数是应用程序类的RUN()函数。RUN()函数将接收到的消息都交给主窗口的窗口函数OnWndMsg(),由OnWndMsg()函数负责将消息分类并交予不同的消息处理函数去处理。,消息映射表,MFC在每一个能够接收和处理消息类中,定义一个消息和消息处理函数静态对照表,该表称为消息映射表。该类能够处理的所有的消息及其对应的消息处理函数的地址都列在该表中。,在类中加入静态消息映射表,在.h 文件中加入:DECLARE_MESSAGE_MAP()在.CPP文件中加入:BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)ON_WM_PAINT().END_MESSAGE_MAp(),消息映射表示例,BEGIN_MESSAGE_MAP(CExam1_1App,CWinApp)/AFX_MSG_MAP(CExam1_1App)ON_COMMAND(ID_APP_ABOUT,OnAppAbout)/AFX_MSG_MAPON_COMMAND(ID_FILE_NEW,CWinApp:OnFileNew)ON_COMMAND(ID_FILE_OPEN,CWinApp:OnFileOpen)ON_COMMAND(ID_FILE_PRINT_SETUP,CWinApp:OnFilePrintSetup)END_MESSAGE_MAP(),消息处理宏格式,例3-3创建一个单文档的MFC应用程序Exam3_3,并实现功能:当在视图中双击鼠标右键时,弹出对话框,显示鼠标的坐标。,如何处理窗口消息,所有基类均没定义该消息的处理函数,3.3.3 消息处理路径,窗口消息的处理:OnWndMsg()搜索窗口类的消息映射表,如果找到了匹配的消息处理函数,就执行消息处理函数 如果找不到,继续搜索该窗口类的基类,如果找到了匹配的消息处理函数,就执行消息处理函数;如果还没有找到,则把消息交给默认窗口函数DefWindowProc()处理,如何处理命令消息,从理论上讲,所有从基类 CCmdTarget类派生的类均可处理命令消息,MFC应用程序框架将依次检查基本类的消息映射表。,视图类,文档类,文档模板类,框架窗口类,应用程序类,界面变灰,命令消息的处理,OnWndMsg()函数会将命令消息分发给窗口类的OnCommand()函数OnCommand()函数调用成员函数OnCmdMsg()函数,该函数依次搜索视图类、文档类、文档模板类、框架窗口类和应用程序类及其基类中的消息映射表,搜索到消息处理函数,搜索到消息处理函数则执行消息处理函数如果全部查找完毕,依然不能处理,则该命令消息所对应的界面元素变灰。,如何处理控件消息,控件消息的处理,把消息交给控件所属的类,如果能够处理,执行消息处理函数如果控件所属的类不能处理,调用控件的父窗口对应类的OnCmdMsg(),搜索父窗口对应类的消息映射表,以获得处理该消息的函数,