和vc visualcmfc编程实例1 3怎样应用MFC创建一个窗口_第1页
和vc visualcmfc编程实例1 3怎样应用MFC创建一个窗口_第2页
和vc visualcmfc编程实例1 3怎样应用MFC创建一个窗口_第3页
和vc visualcmfc编程实例1 3怎样应用MFC创建一个窗口_第4页
和vc visualcmfc编程实例1 3怎样应用MFC创建一个窗口_第5页
已阅读5页,还剩685页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第一部 基础知第1 窗 API环境 小 第2 类基 CObjectCCmdTarget CWinApp(O/C/W)CView 框 小 第3 消息处 使用SetCapture( 小 第4 绘 屏 53内 信 画 画 滚 路 控制什么时候在哪里绘图处理 小 第二部 用户界面实5应用程序与环 例 规划MFC应用程序例 用AppWizard创建一个MFC应用程例 用ClassWizard创建一个类例 例 保存应用程序屏幕例 例 动态改变应用程序图标例 提示用户优先选项例 例 例 6菜 例 例 例 例 例 例 例 例 例 7例 创建弹出式菜单和状态 例 例 例 为按钮添加 例 例 例 例 例 例 例 第8 视 例 例 例 例 例 例 第9 框和条例 例 例 例 例 例 例 消息 例 第10 控件窗 例 例 例 例 例 例 例 分隔线控 第11 绘 例 绘制图 例 绘制文 例 例 例 例 第三部 内部处理实12消 重定向命令消息创建自己的窗口消息13文件、串行化和数据库例 二进制文件例 标准I/O文 例 例 例 例 例 透明地更新串行化的文档例 例 例 例 DAO数据库 14杂类例 例 例 剪切、拷贝和粘贴二进制数据例 数组函 例 列表函 例 映像函 例 例 时 第四部 打包实15 例 静态C/C++ 例 动态C/C++ 例 动态MFC扩展类 例 303第五部 附附录控件窗口风 附录消息、控件通知和消息映像 附录其他应用程序类附录开发中注意事项附录MFC快速参考指南第一部分第一部分用VisualC++和MFC创建的应用程序大多会自动生成窗口,并且可以处理消息,进行绘图。Microsoft在这方面做了大量的工作,隐藏了内部工作,使我们能够更轻松地创建一个一般的应用程序。然而,当用户不能实现他们想要实现的功能时,适当地了解内部工作机制,对于消除编程上的困惑会有好处。更重要的是,知道怎样执行任务(诸如把窗口放置到什么地方,从什么地方获得一个消息和在任意地方绘图),有助于分清用户的应用程序和由VisualC++和MFC自动提供的限于窗口、消息和绘图的应VisualC++应用程序有四项主要基本知识:创建一个窗口、了解其他的MFC类、把消息发送到一个窗口和在一个窗口内绘图。当然还有其他一些基本知识,我们也将在涉及时适当地进行讨论。不过本部分将讨论以下四项基本知识。在第1章中,我们首先讨论在使用和不使用MFC的情况下创建一个窗口,以便清楚地了解MFC是如何工作的。MFC窗口既可以由属于MFC的C++类创建,也可以由一个早于并存在于MFC之外的非C++窗口类创建。进一步窗口类并讨论那些由Windows操作系统提类在第2章中,全面地讨论MFC提供的强大的功能。大多数MFC类是从三个MFC基类(CObject、CWnd和CCmdTarget)派生来的。并讨论构成一个应用程序的MFC类、支持窗口界面的MFC类、用来绘图的类、文件的类、数据和数据库的类和因特网在第3MFC应用程序是怎样通过消息与外界及应用程序进行通信的。还将讨论四种消息类型,并一个消息通过接收消息的类。最后将探讨该路径上的重定向消息。在第4章中,讨论在窗口中绘图的方法,包括绘图工具、绘图用的颜色、在屏幕或第1章 在本章中,讨论MFC用户界面的基本要素:窗口。在此基础上比较API窗口和MFC窗口的异同,描述如何创建一个窗口、销毁一个窗口和控制Windows操作系统与窗口的通窗口是屏幕上的一个矩形区域,应用程序在该区域中显示数据并等待鼠标点击。Windows应用系统的用户界面可以包含许多窗口,每个窗口都有不同的特点,但都是互相联系的,如图1-1窗应用程序的主窗窗窗 窗图1-1Windows应用程序用户界面包括的窗在这么窗中,本类只有种(Overlapped)窗口,弹出(Popup)窗口窗口(Child)。在它们之间并没有太多内在的差异,但是使用不同的窗口风格,它们的外观是不同的(见图1-2。窗口弹出窗口通常以框和消息框的形式与用户子窗口通常用在视图(View)窗口和弹出窗口的主要区别是弹出窗口出现时可以没有标题(也称为标题栏)与窗口或弹出窗口的主要区别是子窗口只能出现在另一个窗口中,并且子窗口的任何多余部分都被该窗口移去或剪切掉。另外,子窗口是唯一不能有菜单条的窗口。参见图1-3中的Windows应用程序,其中包括窗口、弹出窗口窗口第第1章 窗图1-2属于桌面 图1-3由窗口、弹出窗口窗口组成的窗口应用程每个窗口都有由系统绘制的“非客户区”和由应用程序绘制的“客户区”。系统可以绘制图1-4显示的其中一个或者全部特征,当然也可以把所有的特征留给你去绘制。任任务 最小化按 应用程序图最大化按 菜单关闭按 垂直滚动 水平滚客户图1-4窗口的非客户区可以由系统选每个窗口代表内存中的一个窗口对象,并由该窗口对象告诉Windows操作系统将窗口绘制在何处,以及在对鼠标单击、键盘按下(假设该窗口拥有输入焦点)和时钟终止等作出4第一部分基础知识应时应调用什么应用程序。窗口对象自身是窗口类的一个实例,它不是VisualC++的类,而是存在于VisualC++之外,并早于VisualC++的Windows所属的类。然而,就像C++的类一样,窗口类为每个基于它创建的窗口定义了若干特征,如背景色和往何处发送消息等(见窗口对窗口①使用RegisterClass(函数创建窗口 ②窗口对象由CreateWindow(

窗象列表,并告诉每个对象屏幕上绘制自 indows操作系统提供了一个扩展的应用程序接口(API),可以用来创建和这些窗口对象。调用CreateWindow()SetindowLong()函数可以改变由窗口类定义的特征;调用Moveindow()函数可以移动窗口;调用Destroyindow()可以MFC又能做些什么呢?窗口和MFC环MFC窗口是C++和WindowsAPI调用的综合。事实上,MFC窗口提供了许多(但不是全部)WindowsAPI的C++封装,从而减轻了编写Windows应用程序时一些乏味的工作,并提供MFC窗口不对窗口对象进行直接控制,而在API环境中却是可以的。如果不能在API环境中实现某项功能,那么肯定也不能在MFC环境中实现。举例来说,MFC库的CWnd可以创建一个窗口,但它只是过去在API环境中使用的API调用的封装。微软已经把在MFC库中创建和一个窗口的逻辑作为真正的C++封装和控制。然而,创建MFC窗口是复杂的,首先,创建类CWnd的一个实例,然后调用类CWnd的一个成员函数,该成员函数调用API中的CreatWindow()函数。返回的窗口句柄(这只是指向窗口对象的注意因为窗口在内存中创建,而内存经常发生变化,窗口地址可能是经常变化的。因销毁窗口同样也是复杂的,必须确保销毁了该窗口对象,以及封装该窗口对象的CWnd实例。虽然CWnd对象知道窗口对象,但是窗口对象并不知道CWnd对象(见图1-6)。第1章 窗口 CWnd类对

窗口对窗①首先,用AfxRegisterClass(函数创建一个窗口

调用图14中看到的

::CreateWindow

屏幕上绘制自图1-6应用两个对象创建MFC窗尽管窗口应用程序的用户界面可以由几十个、甚至几百个窗口构成,但是大多数窗口还是由不到十个的窗口类创建的。即使在应用程序中有一千个窗口,每个窗口也只能是三种基本类型之一:窗口、弹出窗口或子窗口。怎样应用MFC创建一个窗可以用MFC的CWnd类创建一CWndBOOLb=wnd.CreateEx(ExStyle,ClassName,WindowName,Style,x,y,Width,Height,Parent,,()HWNDhwnd=::CreateWindowEx(ExStyle,ClassName,WindowName,Style,x,y,Width,Height,Parent,,Instance,Param);因为CWnd类只是封装了用于创建窗口的WindowsAPI函数(CreateWindowEx()),因此,从本质上讲,创建窗口所必须的参数在API环境和MFC环境中是相同的:参数Style和ExStyle决定窗口的“外观”和类型(、弹出、子窗口)参数ClassName参数WindowName决定窗口标题内容(如果窗口标题有内容)参数x,y,Width和Height参数Parent指向拥有该窗口的窗口指针(如果有这样的窗口)参数指向内存中的一个对象,作为它的菜单使用—除非创建一个子窗口,如果IDnumber。参数Instance识别该窗口属于哪个应用程序,以便发送到该窗口的消息能被发送到正确的应用程序的消息队列中。CWn类填入InstanceNULL。窗口句柄自动地保存在CWnd类的m_hWnd成员变量中,这面的图1-6中可以看到6第一部分基础知识现在既然已了解了有关创建窗口的基本知识,那么让我们进一步来看看填写这些参数的规则。该参数是一个零结尾的文本串,用该串指明在窗口标题栏中显示的内容。如果窗口没有标题栏,该参数可以为零(0)。然而,某些通用控件也使用该参数。例如,按钮控件把该参数的内容放在按钮的表面。在创建窗口标题栏后,可以用类CWnd的成员函数endoTxt这两个是32位的参数,用来指定创建什么类型的窗口。可以选择多种类型,如下面的例子所示:用于创建三种基本窗口类型的风格,用WM_CHILD创建一个子窗口;用WM_OVERLAPPED创建一个窗口。如果不为窗口指定任何一种风格,那么窗口风格默认为WM_OVERLAPPED。用以增添窗口的非客户区特色的风格。例如,可以用WS_VSCROLL为窗口添加一个若在CreateWindow中定义(使窗口可视

(窗口输入图1-7非客户窗口风格用来增添窗口由每个通用控件定义的风格。例如,用来标识控件组起始控件的风格,或者当用户敲击Tab键控制焦点在窗口中变化时,用想了解的有关窗口风格的例子,请参阅附录A在创建窗口以后,可以用CWnd的成员函数ModifyStyle()和ModifyStyleEx()改变窗口风格。某些风格可能要求重画窗口,这时,可以给ModifyStyle()函数添加第三个参数,自动激发类CWnd的成员函数SetWindowPos()做重画窗口工作。第1章 CWndwnd.ModifyStyle事实上,给ModifyStyle或ModifyStyleEx()添加任何第三个参数,都需要添加下面的SetWindowPos()选项:SWP_NOZORDER、SWP_NOMOVE、SWP_NOACTIVATE和X和Y位置参这是两个32位的参数,用于以像素为单位指定窗口的位置。创建窗口和弹出窗口时,X和Y是相对于桌面窗口左上角的位置。而创建子窗口时,X和Y是相对于父窗口客户区的左上角位置。如果把X和Y参数都设置为CW_USEDEFAUT,那么系统将自动为窗口选定一个位置。系统层叠排列这些新窗口(见图1-8)。第一窗 下一个窗 第三个窗图1-8CW_USEDEFAULT允许系统自动设定窗口位然而,如果X和Y参数都设置为CW_USEDEFAUT,那么子窗口在创建的时候,总被创建在(0,0)创建窗口以后,可以用类CWnd的成员函数MoveWindow()这是两个32位的参,用以像为单指定口的小。如将参数idth和Height都设置为CW_USEDEFAUT,则系统将根据桌面窗口的大小,自动选定窗口的大小。然而,对于一个窗口说,统将建一长和均为0口。如果窗口的风格是WS_MINIMIZE或WS_ IZE,那么系统将忽视用户为idth和Height设置的任何值。创建窗口以后,可以用类CWnd的成员函数MoveWindow()Z-当几个窗口占据屏幕上同一区域时,Z-Order决定哪个窗口显示在哪个窗口之上。Z-Order(Z顺序)中的Z来源于坐标X-Y-Z轴的Z轴,其中Z轴垂直屏幕,并由屏幕指向外面。当窗口最初被创建或选中时,则窗口将出现在Z-Order的顶层。然而,该窗口不可能出现在一个最顶层窗口的上面,除非该窗口也是最顶层的窗口。“最顶层”窗口用WS_EX_TOPMOST窗口风格创建,并显示在所有非最顶层窗口的上面,而与该窗口是不是当前选中的窗口无关。创建窗口后,可以用CWnd的成员函数SetWindowPos()改变窗口的Z该参数是指向类CWnd对象的指针,根据创建的窗口类型标识是父窗口还是物主窗口8第一部分基础知识如果创建的是一个子窗口,那么用该参数来标识它的父窗口(该子窗口所放置的并为之所截断的窗口)。该值不能为NULL。子窗口只能出现在它的父窗口里面,当父窗口被销毁时它们也被销毁,并且当父窗口被隐藏或最小化时它们也被隐藏。如果创建的是窗口或弹出窗口,用该参数来标识物主窗口。如果该值为NULL,则桌面窗口成为物主窗口。从属窗口总是显示在它们的主窗口上面,并且随着物主窗口的销毁而被销毁;物主窗口最小化时,则从属窗口被隐藏;但当物主窗口被隐藏时,从属窗口并不被隐藏。一个子窗口可能是另一个子窗口的父窗口,但绝不可能是一个物主窗口。如果试图使一个子窗口成为一个物主窗口,那么系统只能使那个子窗口的最顶层窗口作为物主窗口。图1-9是这些关系的概述。①或弹出窗口对③弹出或窗口对象图1-9物主、父、子窗口的层次关可以用CWndSetOwner()改变已有窗口的物主窗口,用CWnd的成员函数SetParent()改变父窗口。菜单或控件ID该参数用来标识菜单()句柄或控件(Control)ID,这要依赖于创建的窗口是子窗口、如果创建的是一个子窗口,用该参数标识控件ID,控件ID通常用来帮助父窗口识别子窗口。因为该参数寻求一个变量,因此,需要用类型重载变量定义控件II102⋯,(H)如果创建的是一个窗口或弹出窗口,用该参数定义窗口的菜单。若该值为则菜单默认为在该窗口的窗口类中定义的任何菜单;如果窗口类也没有指定的菜单,Hh=::Load(AfxGetInstanceHandle(),MAKEINTRESOURCE第1章 这里的xx是应用程序资源里面的菜单 可以用CWnd的SetDlgCtrlID()改变已有子窗口的ID。用类CWnd的成员函数Set ()改前面已提到,CWnd类将填入该参数。CWnd通过调用AfxGetInstanceHandle()获得该实例(Instance)。一个应用程序的实例从本质上标识了哪个程序在内存里。AfxGetInstanceHandle()该32位参数(Parameter)是可选的。它通常是指向一个结构或者类对象的指针,而该结构或者类对象是创建某种类型的窗口时需要提供的。例如,当用MDI 窗口类创建窗口时需要该参数提供一个 CRETESTRUCT结构的指针。类名(ClassName)参数是一个零结尾字符串,当创建一个窗口时,用来标识使用那个窗口类。关于窗口类和窗口处理,将在本章后面的内容中详细讨论。该参数不能为NULL一个非常一般的MFC窗口时,使用AfxRegisterWndClass(0)填入该参数。怎样使用MFC销毁一个窗如前面所提到的一样,删除一 MFC窗口可能有些烦琐,必须按下面的顺序删除两个pWnd->DestroyWindow();//destroysWindowObjectdeletepWnd; //destroysCwndObject也可以只删除CWnd对象,因为DestroyWindow()是从CWnd的析构函数中调用的,但提倡使用这种方法。销毁一个窗口而不先调用DestroyWindow()函数,将使某些析构消息不能如果需要在销毁窗口的同时销毁CWnd对象,则应该在CWnd的派生类中添加下面的重载函CYourWnd::PostNcDestroy({delete}PostNcDestroy()是销毁窗口前调用的最后一个成员函数。但是,几乎不需对该函数进行重载,因为CWnd和派生类一般是嵌在另一个类中或建立在堆栈中的。如果一个窗口是用WindowsAPI在应用程序建立之前或外面创建的,并且需要把它封装到CWndwnd.Attach这里的hwnd是已有窗口的句柄。Attach()只是把CWnd的成员变量m_hWnd赋给hwnd。也可以使用 并返回该CWnd对象的指针。如果不存在这样的CWnd10第一部分基础知识窗口C++C++之外的窗口专有的类。窗口类的作用就像一个模板,可以由此创建其他窗口,并可共享某些特征,包括下面所示的特征:类图标如果窗口有图标,用它来指定在窗口的左上角处所画的图标。类菜单如果窗口有菜单,用它来指定窗口中显示的菜单。窗口窗口与环境的交互是通过发送和接收消息来实现的。如果系统要求窗口自己进行绘制,系统给它发送一个WM_PAINTWM_DESTROY消息。这些消息都由窗口的窗口进程处理,该窗口进程的地址在窗口类中定义。对于发送到由相同的窗口类创建的窗口的消息,系统采用完全相同的窗口进程进行处理。相同的窗口进程是怎样所有的窗口的?它是怎知道窗口A画在(10,34),而窗口B画在(56,21)呢?所有这些工作的完成只需使用窗口的窗口对象。例如,所有用按钮窗口类创建的窗口,都使用相同的按钮窗口进程。如果一个WM_PAINT消息发送到其中任何一个窗口,则按钮窗口进程根据每个窗口的窗口对象指定的大小、位置和风格画出确切的按钮(见图1-10)。窗口对BUTTON”的窗口进程搜索窗口对象,以“CheckBox”,则绘制一个复选框父窗①用“BUTTON”口类创建的窗

④如果风格是“Push

口进程也搜索窗口对象以图1-10按钮窗口进程使用窗口对象指定对哪个窗口进行第第1章 怎样使用MFC 一个 系统全局类(SystemGlobal 应用程序全局类(ApplicationGlobal应用程序局部类(ApplicationLocal 要创建一个窗口类,可以先创建WNDCLASS结构的实例,然后用MFC类库的Class()它。也可以用MFC类库的AfxRegisterWndClass()来创建一个基于调用参数WNDCLASS使用 )函数一个窗口AfxRegisterWndClass()函数在使用上是非常自动化的,一些通常需要你提供的参数都能自己填入,甚至连新的窗口类的名字也能自动产生。LPCTSTRlpszClassName=AfxRegisterWndClass(UINTnClassStyle,HCURSORhCursor=0,HBRUSHhbrBackground=0,HICONhIcon=0);根据传给该函数的参数,为新的窗口类产生名字。如果传输的参数完全相同,那么创建AfxRegiterClass()。窗口类风格由下面选项列表中一系列标记的 (OR)运算提供类风 CS_OWNDC 为该窗口类创建的每个窗口分配唯一的设备环境。有关设备环境的更详尽资料见第4章CS_PARENTDC 从系统高速缓存中检索设备环境,然后设置该设备环境的剪裁区,以组合到父窗口中,以便子窗口能画在父窗口上 分配一个设备环境给所有由该窗口类创建的窗口使CS_SAVEBITS 由该类创建的任何窗口的 区将被保存,以便窗口移动或关闭时,不需要重画基础窗口—这对快速机器来说作用不大 当计算机的显示卡和CPU速度较慢时,这两种风格有用。添加这些风格后,当 如果设置该风格,则该类是应用程序的全局类,否则它是一个应用程序局部类 禁用系统菜单中的关闭命CS_DBLCLKS 如果未设置该参数,并且双击由该窗口类创建的窗口,则传送给应用程序的将不是双击,而是两个相继完成的单击12第一部分基础知识图标该参数是显示在窗口左上角的图标的句柄,但只适用于使用WS_SYS 的窗口风格应用程序主窗口的图标也显示在任务栏上。如果将该参数设置为 NULL,并且设置了WS_SYS 风格,则系统将提供一个默认的图标。在MFC环境中,绝大部分图标已被处理过,用Wnd的SetIcon()可改变已有的图标。光标该参数是鼠标移经应用程序窗口的客户区时,将要显示的鼠标光标句柄。如果将该参数设置为NULL,则显示的是箭头光标。可以用下面的语句装载一个光标:HICONhIcon=AfxGetApp()->LoadCursor这里的xx是应用程序资源中光标的名字或ID这里指定的光标意味着是该窗口的默认光标。如果想动态地改变光标形状,则应该处理该窗口的WM_SETCURSOR消息,并用SetCursor()来改变光标形状(见第8章例33)。当系统创建窗口时,先在显示窗口的地方画一个矩形区域,以擦除该区域的背景色。该参数指定填充该矩形域时所用画刷的句柄(参见第4章有关画刷的详细内容)。为窗口类创建的画刷对象在该类退出时被自动释放。 (HBRUSH)设置该参数为NULL,则在画一个窗口之前,系统不对窗口进行擦除。在非客户区的绘制NULL,应确认窗口是画全部客户区,还是处理WM_ERASEBRGND消息以擦除背景颜色。使用AfxRegisterClass()第1章 BOOLAFXAPIAfxRegisterClass(WNDCLASS•这里的WNDCLASS结构定typedefstruct_WNDCLASSUINT //styleofthe //functioncalledbysystem//ithasamessagefora//createdwiththis //extrabytestoaddto//WNDCLASSstructure// //extrabytestoaddtothe//Objectscreatedwiththis //instancethatownsthis //icontobeusedwhen//disysan //cursortousewhenmouseis//awindowcreatedwiththisclass //backgroundcolortousewhen//erasingthebackgroundarea//awindowcreatedwiththisclass nametobeusedwhen//creating fora//createdwiththisclass //theclassnamethatidentifies//thisWNDCLASSforthe}类名参数是用来标识新窗口类的零结尾字符串。可以任意命名窗口类,但是不要与已有的窗口类同名,除非想使该类无效。正如前面所提及的,系统从应用程序局部类开始,在三个列表中寻找类名匹配,如果在该列表中记录了一个与系统全局类同名的类,则应用程序将使用新记录的类。该参数指向应用程序资源中的菜单名。在MFC环境中,大多数情况下由系统载入菜单,但可以在此处指定菜单名。如果使用资源ID,也可以采用下面语句:MAKEINTRESOURCE(IDR_这将成为该窗口的默认菜单。若指定该值为NULL,系统将使用在类CWnd的CreateEx()14第一部分基础知识用以标识哪个应用程序包含了该窗口进程。在MFC环境中,默认的窗口进程为AfxWndProc(),AfxGetAfxWndProc(可以用AfxGetInstanceHandle(填入InstanceClassExtra和WindowExtraClastra和WindowExtra参数提供了一种数据的方法,允许应用程序自身将所属的数据到窗口对象或的窗口类中。类时,ClassExtra指定在类的末尾分配的额外字节数;创建窗口对象时,WindowExtra指定添加到该窗口对象尾部的额外字节数。在这两种情况下,这些额外字节都应用程序用来属于窗口或窗口类的消息。然而,由于CWnd对象与一个窗口关联,并且一个CWnd对象可以的信息量若不比额外字节的0。怎样销毁一个MFC窗口通过取消窗口类的销毁窗口类。但是,如果用AfxRegisterWnd()或AfxRegisterWnd-Class()一个类的话,那么在应用程序结束的时候,类的会自动取消,即使应用程序应用程序可能运行在一个已若干个窗口类的环境中。其中的一些是由操作系统(Windows3.1/95/98/NT)提供的;另一些是由MFC提供的。由系统提供的控件窗口也叫做通用控件。Windows3.1类创建的窗类创建的窗弹出式菜单窗口(弹出式菜单是位于弹出窗口中,并框MDI子窗口区Windows3.1类创建的类创建的按钮控件窗组合框控件窗静态控编辑控件窗列表框控件窗Windows95/NT类创建的窗类创建的窗进度指示控件窗标题控件窗口(标题控件常驻留在列表视图控件的窗Rebar窗部类创建的窗类创建的窗CWnd窗MFC框架和视MDIMFC控制条窗窗口有三种基本的类型—窗口、弹出窗口窗口。但在一个MFC应用程序中,可以用不同的方法使用它们。除非特别提到,封装这些窗口的类都从CWnd类派生。下面列出的框应用程序用来提示用户作出反应的弹出窗口。条保持打开状态,作为的框状态栏一个子窗口,通常位于应用程序主窗口的底部,并用来显示正在使用令的帮助框架窗口一个窗口,通常在应用程序中作为所有其他窗口的父窗口和物主窗口。框架文档/视图实际上是由两个MFCMFC应用程序是以“文档文MFC文档类对象,从磁盘中读入一个文档,赋予其成员变量;然后,创建一个或多个视图类对象,以显示这些成员变量。如果创建了多个视图类对象,则一个文档将有多个视图。由于MFC文档类没有关联窗口,因而它不是从CWnd类派生的。文档模 实际上没有窗口,而是在打开一个文档时,应用程序用来确定创建什么样MFC文档类对象和MFC视图对象。理论上讲,一个应用程序可以有多个文档模板,并允许一个应用程序处理多种类型的文档,然而,绝大多数应用程序只有一个模板。MFC文档模板不16第一部分基础知识是从CWnd类派生的。想地了解有关文档模板的内容,请参看第2章本章中最后一个问题是桌面窗口(DesktopWindow),所有其他窗口都显示在它的上面,并最终属于它。桌面窗口自身是一个弹出窗口,并且是最高阶弹出窗口。最高阶窗口列表是由口理的此叫窗管列表(WindowsManagerList)。窗口管理器应用该列表桌面窗口,如图1-1所:口对果屏幕需要刷新,管理器列

口对

后,窗口管理器每个窗口进程重绘制自窗口的每个子窗口重绘制自框架 子窗口口对 象列

口,以此类图1-11窗口管理器通过使用窗口管理器列表桌面窗若要获得桌面窗口的句柄,可以用::GetDesktopWindow()可以用带SPI_SETDESKWALLPAPER参数的SystemParametersInfo()在桌面上设置一幅 _NotifyIcon()将图标放置到外壳盘(S Tray)里—以后在任务栏里发现的小图可以用::FindWindow()可以用WindowFromPoint()可以用::GetSystemMetrics(SM_CXSCREEN)和::GetSystemMetrics(SM_CYSCREEN)获得屏幕尺寸。使用MFC类和 的特征—窗口类(不是C++类)创建用户界面窗口的MFC应用第第1章 用MFC三种类型的窗口 窗口、弹出窗 第2 到目前为止,我们只讨论了MFC的CWnd类。在本章中,讨论MFC提供的其他重用户界面的类,包括CWnd本章的目标不是成为MFC参考指南,而是综合论述MFC所能提供的功能。对于任何在本章中没有讨论的类,或有关某一特定的类的详细描述,请参考有关MFC文献。大部分OLE类没有在本章中论及大多数MFC类是从三个基类(BaseClass)派生的:CObject、CCmdarget和CWnd。CCmdTarget派生于CObject类,而CWnd于CCmdTarget类。从CObject派生的类,具有在运行时获得对象大小和名字的能力;从CCmdaget派生的类,能够处理命令消息;从CWnd派生的类,能控制它们自己的窗口。CObject类本身提供的功能较少,主要工作由六个伴生宏( companionmacros)完成。CObject和这些宏一起,允许CObject的派生类在运行时获取类名和对象大小,创建一个类对象而不必知道类名,以及允许从文件设备中存取一个类的实例而不必知道类名。DECLARE_DYNAMIC(CYourClass) //inthe.hfileIMPLEMENT_DYNAMIC(CYourClass,CYourBaseClass)//inthe.cppfile可以用CObject::GetRuntimeClass()下面这些宏包括了前面两个宏的功能,但是允许在不知道类名的情况下创建一个类的实例。DECLARE_DYNCREATE(CYourClass) //inthe.hfileIMPLEMENT_DYNCREATE(CYourClass,CYourBaseClass) //inthe.cppfile在不知道类名的情况下,可以用CRuntimeClass::CreateObject()创建一个运用这些宏的类第2章 下面这些宏包括了前面所有宏的功能,但还允许在不知道类名的情况下,把一个类的实例存到磁盘上。DECLARE_SERIAL //inthe.hIMPLEMENT_SERIAL(CYourClass,CYourBaseClass,schema)//inthe.cpp 这在第1章中已讨论过,CWnd的成员函数封装了WindowsAPI中负责 O表示该类是从CObject派生的使用Developertudio的AppWizard(应用程序向导)创建MF应用程序时,应用程序从四个 是应用程序的“文档类”,负责装载和文档。文档可以是从文档到网络 根据所建的应用程序类型,应用程序中AppWizard包含相应的基类。框用序用户界面只有一个框,没有框架类、文档类或视图类。框应用程序只用应用程序类的派生类—CWinApp。框用MFC的CDialog类创建,这将在随后部分讨论。单文档界面应用程序能在某个时间内装入和编辑一个文档,使用了前面提及的所有四个多文档界面应用程序一次可以装载和编辑多个文档,并且不但使用了所有四个基类, 章中描述的文档子,参见例220第一部分应用程序类CinAPP(O/C/W)是应用程序开始后创建的第一个对象,并且是在结束前最后一个执行的对象。起动时,应用程序类负责创建应用程序的其余对象。对于一个框应用程序,应用程序类应 CDialog创建一个框对于一个SDI应用程序,应用程序类创建一个或多个文档模板(见下面的讨论),然后用对于一个MDI应用程序,在主框架类中,应用程序类创建一个或多个文档模板,然后用模板打开一个空文档。在下一章中还将看到,应用程序类也同操作系统交互,作为中继,将鼠标信息和键盘输入传给应用程序的其余部分。应用程序打开一个文档时,文档模板定义创建什么样的框架、文档和视图。要创建一个文档模板,要么为SDI应用程序创建一个CSingleDocTemte类,要么为MDI应用程序创建CMultiDocTemte类,并且用三个类的指针对它进行初始化。(IDR_APPTYPE,RUNTIME_CLASS(CAppDoc), //YourClassRUNTIME_CLASS(CChildFrame), //YourFrameClassRUNTIME_CLASS(CAppView)); //YourViewClass这里的RUNTIME_CLASS宏返回一个指向类的CRuntimeClass结构的指针,该结构用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE宏填加到类中。文档模板通过用CRuntimeClass::CreateObject()函数创建一个所有三个类的实例来打开一个文档。CWinApp类自身是从CinThread派生的。CWinThread类封装了系统中用来创建和应用程序线程的WindowsAPICWinThread类的另一个实例实现应CinApp类代表主要的执行线程。此框架类CFrameWnd(O/C/W)是应用程序运行时创建的第二个对象,负责显示和监督用户对应用程序其余部分令。SDI应用程序,框架类是从CFrameWndAppWizard自动命名为:MDI应用程序,框架类派生于CMDIFrameWndAppWizard自动命名为CMainFrame。在MDI应用程序中,每个打开的文档有一个子框架类,每个子框架类是从对于一个框应用程序来说,没有框架类。面已提过,一个框应用程序是一个应用程序类和一个框类组成的 通常,文档类 (O/C)是应用程序打开一个新文档或一个已存在的文档时创建第2章 对象。文档类负责将一个文档赋给它的成员变量,并允许视图类编辑这些成员变量。一个文档包括从图形文件到可编程控制的任何内容。文档类派生于CDocumnt,AppWizard自动命名为CXxxDoc,Xxx是应用程序名。CView窗口分区类,即CSplitterWnd,允许文档有多视图;这些视图以由相同视图类的一些实例创建,也可以由完全不同的视图类实例创建。Appizard允许视图类从几个基类(包括CTreeView、CEditiew、CRichEditiew、CListiew等)之一派生,每一个基类赋予应用程序不同的功能集。有关这些类的例子参见例1Ciew类,不管选择哪个基类,AppWizard自动命名派生类为CXxxView,这里的Xxx是应用程序名。前面已提及,可以从四个基类创建三种类型的应用程序:框、单文档、多文档。下面详细讨论这些应用程序类型。话框构成的(见图2-1)。应用程序 框

②应用程序类创建话框类的实 框类创建其他控件类,这类一起创建了屏幕上的窗

图2-1一个框应用程序由一个应用程序类和一个框类创单文档界面应用程序包以下类:从CWinApp派生的应用程序类、从CFrameWnd派生的框架类、从C 派生的文档类,以及每个文档一个或多个视图类,这些视图类是从一些派生于iew的视图类派生的(见图2-2)。多文档界面(MDI)应用程序包括以下类:派生于CWinApp的应用程序类、派生于CMDIFrameWnd的框架类、派生于CMDIChildWnd的一个或多个子框架类、派生于 框应用程序一般在用户交互要求有限的情况下使用。然而就个人而言,宁愿使用一个带窗体视图(CFormView)的SDI应用程序,而不愿意使用一个框应用程序,这样既利用了创建框应用程序的简单性,又具备了单文档应用程序的文档特性。22第一部分文档应用程序 文档模板

框架

装入一个空的文档视图类的一个实

视图图2-2一个SDI应用程序由应用程序、框架、文档和视图类创文档应用程序

文档模板

子框架

档模板创建文档、框架程序类的一实

装入一个新的空文

视图

类在屏幕上创建窗什么时候应该使用MDI应用程序,而不是SDI应用程序呢?如果在运行期间应用程序只与一个文档有关连,那么就使用SDI方法。但是,如果应用程序能产生多个文档,并对多个文档进行处理(即使这不是完成的),这时应该采取MDI的方法,即使在开始时并没有看到在同一时间修改多个文档的可能。一个MDI应用程序并不比一个SDI应用程序复杂多少,却可以带给用户在同一时间看阅多个文档的方便。除了框架和视图类外, FC还提供了许多其他支持用户界面的类。控件窗类了件。菜单类处理菜单,就如CWnd第第2章 框类 控制条类封装了控制条 条和状态栏)属性类封装了属性表(PropertySheet)和属性页(PropertyPage)通用控件类(O/C/W)封装了通用控件(如按钮、列表框等)的功能。这些类派生于CWnd,继承了诸如ShowWindow()和MoveWindow()之类的窗口成员函数。当这些类创建窗口时,它们使用一个通用控件窗口类。例如,用CButton通用控件类创建一个按钮时,它就用Create(_T("BUTTON"),lpszCaption,dwStyle,rect,pParentWnd,通用控件MFCMFC窗口类CAnimateCtrl动画控按钮控组合框控编辑控标题控列表框控列表控进度指示控滚动条控滑块控微调按钮控静态文本控树型控控日期/时间控月历控热键控工具提示控不是所有的通用控件类都简单地封装一个通用控件窗口类。事实上,有三个MFC类提供了通用控件中没有的功能。下面的表格列出了这些类、它们派生的MFC类和它们所提供的额外派生的MFC类和它们的MFC基MFC所派生的MFC增加的功更好地支持按钮上的位列表框中的复选列表框中用户可拖拉的工菜单菜单类封装了WindowsAPI中用来创建和菜单的函数。 还有两个成员函24第一部分Attach()和Detach()CWnd对象能够封装一个已有的窗口2.3.3框CDialog类封装了用来创建框的WindowsAPI。框是弹出式窗口,在创建时可以用框模板中定义的控件窗口来填充。通用框MFCMFC还有六个类封装了WindowsAPI用来创建通用框的函数。通用框是一些随控件预先装入的用于提示用户输入一些常用信息的框,如装入或的文件名、颜色、字体和打印参数。通用框不但为用户提供了一个熟悉的框,而且节省了书写这些对话的工作量。下面的表格显示了通用框的目的、提供它们的WindowsAPIs和封装这些Windows通用框MFC类及其用途通用 WindowsAPI调 MFC选择颜 打开/保存文 查找或替换文 ::Re

选择字 设置打印 打 控制控制条类(O/C/W)封装了为应用程序提供、状态栏、条和 的WindowsCToolBar(O/C/W)和CToolBarCtrl(O/C/W)创建和维护一个工具栏。CToolBarCtrl类封装了系统提供的窗口类oolbarWindow32的功能,并由该类来做实际的的创建和工作。而CoolBar类是常的MFC。CoolBar能提供比CToolBarCtrl的功能,但必须以开销的内存为代价。CStatusBar(O/C/W)和CStatusBarCtrl(O/C/W)。CStatusBarCtrl类封装了系统提供的窗口类msctls-statusbar32,并由该类来做实际的状态栏的创建和CStatusBar类就是通常的MFCStatusBar能提供比CStatusBarCtrl的功能但必须以开销的内存为代价来支持它。CDialogBar(O/C/W)类创建和条。一个条是框和的混和产物,它显示一个框模板,但却象一个一样浮动并停靠在主框架窗口中。CRebar(O/C/W)和CRebarCtrl(O/C/W)类创建和Rebar。Rebar是窗口控件,可以包含一个、一个条和任何其他子窗口。它们提供了一个移动条(grabberbar)(左边双线),使它们更易于被移动,也更易于在他们的背景上画一幅位图。CReBarCtrl类第2章 封装了由系统提供的Window类ReBarWindow32的功能,并由该类做实际的ReBar创建 工作。换个角度说,CReBar类就是通常的MFC。CReBar提供比CReBarCtrl 属性类封装了WindowsAPI中用来为应用程序提供属性页和属性表的函数。一个或多个属性页出现在属性表中,以创建indows用户熟悉的tabbedCPropertySheet(O/C/W)类创建一个属性表,尽管CPropertySheet不是从CDialog但它们非常相似。CPropertyPage(O/C/W/CDialog)类创建一个属性类,该类是从CDialog8。CDC(0)类封装了WindowsAPI中用来画图的函数。该类也“设备环境(DeviceContext备的最大尺寸和发生作用的方式,设备可以是屏幕或。有关设备环境和CDC类的成员函数的更详细的讨论,请参看第4章。有四个类是从CDC类派生的,并提供了额外功能。CDCCDC通常在堆栈中创建。它的构造函数通过调用CDC::GetDC()为窗口的客户区创建一个设备环境。当例程返回时,CDC的析构函数通过调用CDC:ReleaseDC()销毁该设备。既不麻烦也不复杂,更不会CWindowDC类窗口的非客户区,如CDC客户区一样CPaintDC在被构造以获得设备环境时调用CWnd::BeginPaint()。在这种情况下,设备环境只允许在已被无效化的窗口客户区绘图,而不能在整个客户区绘图。析构时,CPaintDC类调用CWnd::EndPaint()。CMetaFileDC创建一个元文件,元文件是一个磁盘文件,它包含绘制一幅图形时所必需的全部绘图行为和模型。可以通过打开一个元文件设备环境创建一个元文件,然后用画图工具对它进行绘制,就当它是一个屏幕或设备一样。产生的文件可以在未来的某个刻被次读,以建其设备一的像想了解文件参见第4章。设备环境不足以包含绘图功能所需的所有绘图特征,除了设备环,Windows还有其他一些图形对象用来绘图特征。这些附加的功能包括从画线的宽度和颜色到画文本时所下面的表格列出了MFC类,它封装的图形对象,以及在对象中的绘图特征26第一部分MFC图形对象句图形对象目内存中的位画刷特性—填充某个图形时所使用的颜色和模字体特性—写文本时所使用的字体调色板颜画笔特性—画轮廓时所使用的线的粗细区域特性—包括定义它的点CFile()类封装了创建和平面文件的WindowsAPI,三个从CFile派生的MFC类提供附CMemFileCMemClas被打开,并能用它的成员函数对它进行读写,就象一个磁盘文件一样。有关内存文件的例子参见例65。CSharedFile与CMemFile类似,但CSharedFile配置在全局堆上,这使得能用剪贴板和DDE对它进行共享。有关共享内存文件的例子参见例76。CStdioFile参见例64还有一个感的文件类是CFileFind(0),用它来定位磁盘上的本地文件。CFileFind类是另外两个类,CFtpFileFind和CGopherFileFind类的基类,这两个类用来帮助在Internet上定CArchive和串在一个称为串行化的过程中,CArchive类用CFile类将文档的类对象保存到磁盘上。应用相同的次序被恢复。有关串行化的一些例子参见第13章。MFC库具有支持两种类型数据库 封装了大多数数据库厂商支持的ODBCAPI。如果应用程序使用了MFC的ODBC类,它就可以支持任何支持ODBC标准的数据库管理系统(DBMS)。数据对象(DAO)支持一个更新的数据库API,这已被Jet数据库引擎有效三个主要的ODBCCDatabase(0) 用ODBCAPI打开一个DBMS数据库。构造一个CDatabase对象后,可以用它的OpenEx()成员函数创建与数据库的连接。调用CDatabase成员函数Close()结束连接。 第2章 CDBVariant代表一个记录集中的一列,而不必考虑数据类型。想了解ODBC数据,参见例72。CDaoDatabase0)打开一个DAO数据库。CDaoRecordSet(0)容纳记录。COleVariant代表记录列。DAO还包括另外三CDaoQueryDef( CDaoTableDef0)代表一个包括域和索引结构的表定义。想了解一个DAO数据库,参见例73。CArray该类及其派生类支持数据对象数组。一个数组由一个或多个相同的数据对象组成(如整数、类等),它们在内存中相邻,可以通过简单索引它们。CArray类可以动态增CArray的类(如CByteArray、CDWordArray等),允许创建一个类型安全(type-safe)的数组。然而,还有一个CArray<type,arg_type>模板类允许使任何数组类型安全。CList 该类及其派生类支持数据对象的表。一个由一个或多个相同的数据对象组成(如整型、类等),它们在内存中不连续,但数据对象是双向连接的,以便于通过链表前后搜索数据。有些CList的派生类(如CPtrList、CObList等),允许创建一个类型安全的列表。然而,还有一个Clist<type,arg_type模板类使CLit对任何类型都是类型安全的。CMap 该类及其派生类支持数据对象的字典。在一个二进制或文本关键字约束下,数据字典一个或多个相同数据对象(如整型、类等),可以用该关键字检索数据项。举例来说,因为indow不哪个MFCCWnd对哪以序用CMap对象将窗口句柄与它们的CWnd对象关联。有些CMap的派生类(如CMapWordToPtr、CObToString等),允许创建一个类型安全的字典。不过,还有一个CMap<classKey,ClassARG_KEY,ClassVLE,ClassARG_ALUE>模板类,允许创建任何类型安全的映像。MFC库还包括其他一些数CTime和CTimeSpantime_t数COleDateTime和COleDateSpan28第一部分化 DATE数据类型的时间和日期串(见例81)CTime或持的time_t数据类型易于和传输,因为它仅仅是个32位整型数。然而,CTime却没ColeCurrency类具有读入和格式化OLECURRENCYCString类具有文本串的成员函数 CString的数据类型为TCHARCPoint类提供了POINT结构的成员函数,该结构定义了一个点 X和Y坐标CSize类提供了SIZE结构的成员函数,该结构定义了尺寸的宽和高MFC库包含了一些允许应用程序与网络或因特网(Internet)进行通信网络类(NetworkCASyncSocket(0)允许应用程序通过网络与其他应用程序进行通信。CASyncSocket封装了WindowSocketAPI,WindowSocketAPI是基于伯克利的California大学的BSD(伯克利软件中心)的UNIXSocket实现。CASyncSocket能存取网络通信中的位和字节。CSocket是从CASyncSocket派生的类,它允许在网络上发送和接收文件而不必考虑细节问题。可以创建一个CSocketFile对象,并将它与CSocket关联;然后创建一个CArchive对象,并与CSocketFile对象关联。此时发送一个文件只是在网络上将它串行化的问题。MFC有两组因特网类(InternetClasses)(如Web浏览器),而另一组用来增强InternetHTTP服务器软件功能(如Web站点)。MFC的因特网客户类( Classes)封装了Win32InternetExtensions(WinInet),允许用C++语言利用四种协议之一对因特网进行,这四种协议为:文件传输协议(FTP),超文本CInternetSession(0)类有两种方式与eb站点上的文件相互作用,对于简单的阅读或文件,可以用enRL()成员函数,并将Web站点上文件的RL通用源传给。OpenURLMFCURLURL前 返回的因特网类的指

URL前 返回的因特网类的指 上面的每个因特网类都派生于CStdioFile,用户可以读这些文件对象,但不能写。对一个文件进行写操作或执行一些其他特定协议的操作,必须先用CInternetSession的另一个成员函数打开接。该连接仍然在另一个MFC因特网类中返回。第2章 调用的CinternetSession返回的因特网然后,可以用CFtpConnection、CHttpConnection或CGopherConnection的成员函数与另外三个相关的MFC因特网客户类是CFtpFileFind,CGopherFileFind和CGopherLocator。CFtpFileFind和CGopherFileFind派生于前面提及的CFindFile类,可以在Internet上定位文件。CGopherLocator从gopher服务器获得一个gopherCGopherFileFind联系。ISAPI—兼容的HTTP服务器,而 没有用MFC对它提供支持,一个差不多与它兼容CHttpServerCHttpFilterCMemoryState类能帮助你正确内存泄漏。通过创建一个CMemoryState对象,并调用CheckPoint()成员函数,可获得内存的瞬态图;在稍后时刻,用另外一个CMemoryState对象获得另外一个瞬态图,并比较结果。在应用程序的调试版,DEBUG_NEW宏利用这些类自动CException(0)类是MFC处理C++意外事故的设备。有11个派生于CException的类,用来MFC 意外事 使用CArchive 使用CDaoDatabase 使用CDatabase 使用CFile 任何Internet类的错 任何内存错 试图使用一个不支持的函 试图定位或配置一种资 通常用来提示用户发生了某种例{//attemptsomething}30第一部分CATCH(CUserException,{//handle}AND_CATCH(CMemoryException,{//handleanother}{//handleall}MFC同步类用来防止数据对象被破坏。前面已提及,一个MFC应用程序可以同时运行多个线程。如果不止一个这样的线程同时修改相同的数据对象且同时把该数据保存到相同内存地址时,便有可能破坏该数据。在一个多线程应用程序中,四个MFC类和两个MFC辅助类帮助同步数CMutex用来防止多个线程同时同一数据对象。要启用CMutex,先要把它添加到数的员量接造一个MFC类,即CSingleLock,对任何这些成员变量的成员函数CMutex;然后调用CSingleLock的Lock(inttimeout)成员函数。如果别的线程已在访问该数据,则Lock()函数不返回,直到该线程调用Unlock()或超时时才返回。CMultiLock类允许指定多个CMutex对象,以便能同时服务多个(见图2-4)。数据类对线程 线程 ②线程2一直在Lock()处等待,图2-4用CMutex和CSingleLock同步数 与CMutex类基本相同,但是,前者在堆栈中被构造,并有比 基于任何(不仅仅是被另一线程)对数据进行同步。线程将一直等待,直到调用CEvent的SetEvent()和ResetEvent()成员函数允许它们继续为止。 可以方便地将鼠标变为一个沙漏标来指示系统忙。CWaitCursor通常在一个费时任务之前在堆栈中构造,在该任务期间输入。然后,当函数返回时,第第2章 2.11在本章中,我们已经了解了一些MFC我们也简单涉及到类是怎样应用消息和CCmdTarget类进行互相通信的,在下一章中将更 第1章讨论了MFC用户界面的基本要素:窗口、窗口类和CWnd;第2章讨论了构成MFC库的其他类,其是那构成MFC应用程序内核的类。在本章中,讨论MFC类和它们的窗口怎样进行互相通信的。我们发现有三种类型的消息:窗口、命令(Command)和控件通知(ControlNotification)(sent),也可以寄送(post);接着,将一个被MFC窗口进程处理的消息;最后,将讨论重定向消息的方法。第1章已提及,每个窗口使用窗口进程处理发送给它的消息。消息可以来自系统、你的应用程序或别的应用程序。消息告诉窗口进程执行某个任务(如初始化自己、绘制或销毁一个窗口等),或者通知它发生某个(如鼠标正单击窗口)。发送一个消息时,直接调用窗口的窗口进程。通信是即时的,直到窗口进程为调用函数返回一个结果后,应用程序才能继续。寄送一个消息时,把消息发送到拥有那个窗口的应用程序消息队列中。一有空闲,应用程序就搜索消息队列,并在消息队列中处理消息,即从队列中删除它们,并将它们发送到即定窗口。通信将可能延迟,直到目标应用程序获得处理消息的时间。调用函数发送消息后即(见图3-1)。窗口对②被寄送的消息延迟

消息消息

地应用程序消息队列 消息队图3-1发送消息时通信是即时的,而寄送消息时通信可能延第3章消息处 怎样使用MFC发送一个消用MFC发送一个消息的方法是,首先,应获取接收消息的CWnd类对象的指针;然后,调用CWnd的成员函数SendMessage()。LRESULTRes=pWnd->SendMessage(UINT ram,LPARAMpWnd指针指向目标CWnd类对象。变量Msg是消息,ram和lParam变量包含消息的参数,如鼠标单击哪里或选择了什么菜单项。目标窗口返回的消息结果放在变量Res中。发送消息到一个没有CWnd类对象的窗口,可以用下列目标窗口的句柄直接调用WindowsAPI:LRESULTRes=::SendMessage(HWNDhWnd,UINTMsg ram,LPARAM怎样用MFC寄送一个消用MFC寄送一个消息与发送一个消息几乎相同,但寄送时用PostMessage(),而不是用SendMessage();返回值Res也不一样,Res不是一个由目标窗口返回的值,而是一个布尔值,正常情况下,一旦消息被寄送后,应用程序在发送它。但是在特殊情况下,需要你自己去删除一个消息,例如想在应用程序接收到某种消息之前停止应用程序。有两种方法可MFC。BOOLres=::PeekMessage(LPMSGlpMsg,HWNDhWnd,UINTwMsFilterMin,UINTwMsgFilterMax,UINT第二种方法:实际上是等待,一直等到一个新的消息到达队列为止,然后删除并返回该消息。BOOLres=::GetMessage(LPMSGlpMsg,HWNDhWnd,UINTwMsgFilterMin,UINT在这两种方法中,变量hWndNULL,所有窗口消息将被截获。wMsgFilterMin和wMsgFilterMax变量与SendMessage()中的变量Msg相对应,0,0WM_KEYFIRS,WM_KEYLAST或WM_MOUSEFIRS,WM_MOUSELAST,则所有键盘或鼠标的消息将被截获。wRemoveMsg变量指定PeekMessage()是否应该真正地从队列中删除该消息。 )总是删除消息)。该变量可以取两个值:PM_REMOVE,PeekMessage() )当然,如果把消息留在消息队列中,然后再次调用PeekMessage()查看相同类型的消息,34第一部分基础知识lpMsg变量是一个指向MSG结构的指针 MSG包含检索到的消息typedefstructtagMSG hwnd;//windowhandlemessageisintendedfor RAMram; //thetimethemessagewasputinthequeue //thelocationofthemousecursorwhenthe//messagewasputinthe}在MFC应用程序中传输的消息有三种类型:窗口消息、命令消息和控件通知。窗口窗口消息(WindowMessage)一般与窗口的内部运作有关,如创建窗口、绘制窗口和销毁窗当用SendMessage()或PostMessage()发送一个窗口消息时,变量Message、wParam和 定义 定义WM_XXX可以是许多窗口消息之一,如下列窗口:WM_CREATEWM_PAINTWM_MOUSEMOVE有关某些公共窗口消息,参见附录B。若需要窗口消息的完全的列表,请参 MFC文档命令命令消息一般与处理用户请求相关当用户单击一菜单项或时,命令消息产生,并被发送到能处理该请求的类对象(如,装载文件、编辑文本和保存选项等)。当用SendMessage()或PostMessage()发送窗口消息时,变量Message、 CommandID CommandID要么是选中菜单项的ID,要么是被单击的按钮。注意CommandID不能大于一个字长,如果使它大于一个字长,系统就只用0来填充字。某些控件通知也用控件第3章消息处 控件通知为父窗口进一步控制子窗口提供了机会。例如,打开一个组合框时,父窗口可以用组合框初建时得不到的消息填充它。控件通知经历了一个演变过程,因而SendMessage()的变量Message、 定义 定义WM_XXX可以是下面消息中的任何WM_PARENTNOTIFY表示一个控件窗口要么已被建立或销毁,要么鼠标已单击了该窗口。 WM_HSCROLL或WM_VSCROLL第二控件通知格式使 MAND消息,与命令消息共享 lParam变量用来区分是命令消息还是控件通知。控件通知在lParam中有一个有定义的句柄,用来标识发出通知的控件;而命令消息中lParam为NULL。XN_XXXXN_XXX值为EN_CHANGE,告诉父窗口显示在编辑框控件中的文本已发生变化。还有其他一些例子列在附录B中。第三控件通知格式也是最灵活格式,它 WM_NOTIFY消息控件指向NMHDRlParam值指向一个结构,该结构包括有关制作该通知的控件的任何内容,而不受空间和类型的限制,该结构叫做NMHDR。typedefstructtagNMHDRHWND //WindowhandleofControl//makingtheUINT //ControlIDofControl//makingtheUINT //notificationcodeex:the//hasclickedtheControl}NMHDR代表通知消息头(NotificationMessageHeader)。为什么要这个头?因为某些控件用NMHDR作为头发送一个更大结构的消息,即使那些不知道更大结构内容的函数还是能处36第一部分基础知识MFC怎样接收一个寄送的消MFC处理一个寄送和发送消息的唯一明显不同是寄送的消息要在应用程序的消息队列中花费一些时间。在消息泵(mesagepump)弹出它之前,它要一直在队列中。MFC应用程序中的消息泵在CWinApp的成员函数Run()中。应用程序开始运行时,Run()就被调用,Run()把时间分割成两部分。一部分用来执行处理,如取消临时CWnd对象;另一部分用来检查消息队列。当一个新的消息进来时,Run()抽取它—即用GetMessage()从队列中取出该消息,运行两个消息翻译函数,然后用Dispatessage()函数调用该消息预期空闲处

符消

图3-2消息泵执行处理并检查消息队消息泵调用的两个翻译函数是PreranslateMessage()和::TranslateMessage()。目标窗口的MFC类可调用PreTranslateMessageCFrameWnd用PreTranslateMessage()将加速键(如,Ctrl+S文件)转换为命令消息。翻译前的消息通常被处理

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论