《MFC编程案例chapter001.pdf》由会员分享,可在线阅读,更多相关《MFC编程案例chapter001.pdf(17页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、下载用Visual C+和M F C创建的应用程序大多会自动生成窗口,并且可以处理消息,进行绘图。M i c r o s o f t在这方面做了大量的工作,隐藏了内部工作,使我们能够更轻松地创建一个一般的应用程序。然而,当用户不能实现他们想要实现的功能时,适当地了解内部工作机制,对于消除编程上的困惑会有好处。更重要的是,知道怎样执行任务(诸如把窗口放置到什么地方,从什么地方获得一个消息和在任意地方绘图),有助于分清用户的应用程序和由Visual C+和M F C自动提供的限于窗口、消息和绘图的应用程序。Visual C+应用程序有四项主要基本知识:创建一个窗口、了解其他的 M F C类、把消息
2、发送到一个窗口和在一个窗口内绘图。当然还有其他一些基本知识,我们也将在涉及时适当地进行讨论。不过本部分将讨论以下四项基本知识。窗口在第1章中,我们首先讨论在使用和不使用 M F C的情况下创建一个窗口,以便清楚地了解M F C是如何工作的。M F C窗口既可以由属于M F C的C+类创建,也可以由一个早于并存在于M F C之外的非C+窗口类创建。我们将进一步观看窗口类并讨论那些由 Wi n d o w s操作系统提供的窗口类。最后,再看看M F C应用程序中都有什么。类在第2章中,我们将全面地讨论 M F C提供的强大的功能。大多数 M F C类是从三个M F C基类(C O b j e c
3、t、C W n d和C C m d Ta rg e t)派生来的。并讨论构成一个应用程序的 M F C类、支持窗口界面的 M F C类、用来绘图的类、访问文件的类、维护数据和数据库的类和访问因特网(I n t e r n e t)的M F C类。消息处理在第3章中,我们将讨论一个M F C应用程序是怎样通过消息与外界及应用程序进行通信的。还将讨论四种消息类型,并跟踪一个消息通过接收消息的类。最后将探讨该路径上的重定向消息。绘图在第4章中,我们将讨论在窗口中绘图的方法,包括绘图工具、绘图用的颜色、在屏幕或打印机上绘图、绘制位图和图标、绘制矩形和圆、绘制动画。第一部分基 础 知 识下载第1章 窗口
4、在本章中,我们将讨论 M F C用户界面的基本要素:窗口。在此基础上比较A P I窗口和M F C窗口的异同,描述如何创建一个窗口、销毁一个窗口和控制 Wi n d o w s操作系统与窗口的通信问题。1.1 窗口和API环境窗口是屏幕上的一个矩形区域,应用程序在该区域中显示数据并等待鼠标点击。Wi n d o w s应用系统的用户界面可以包含许多窗口,每个窗口都有不同的特点,但都是互相联系的,如图1-1所示。图1-1 Windows应用程序用户界面包括的窗口1.1.1 三种类型窗口在这么多窗口中,基本类型只有三种:重叠(O v e r l a p p e d)窗口,弹出(P o p u p)
5、窗口和子窗口(C h i l d)。在它们之间并没有太多内在的差异,但是使用不同的窗口风格,它们的外观是不同的(见图1-2)。重叠窗口通常用于建立应用程序主窗口。事实上,有时也叫做“主”窗口或者“框架”窗口。弹出窗口通常以对话框和消息框的形式与用户对话。子窗口通常用在视图(Vi e w)中,如在文本编辑器中的文本显示,也用在控件中,如在对话框中的O K按钮。而对那些看起来像按钮或控件的子窗口,也称为“控件”窗口。重叠窗口和弹出窗口的主要区别是弹出窗口出现时可以没有标题(也称为标题栏)。子窗口与重叠窗口或弹出窗口的主要区别是子窗口只能出现在另一个窗口中,并且子窗口的任何多余部分都被该窗口移去或剪
6、切掉。另外,子窗口是唯一不能有菜单条的窗口。参见图1-3中的Windows 应用程序,其中包括重叠窗口、弹出窗口和子窗口。应用程序的主窗口窗口窗口窗口窗口图1-2 窗口风格可以用来区分三种不同类型的窗口图1-3 由重叠窗口、弹出窗口和子窗口组成的窗口应用程序1.1.2 客户区和非客户区每个窗口都有由系统绘制的“非客户区”和由应用程序绘制的“客户区”。系统可以绘制图1-4显示的其中一个或者全部特征,当然也可以把所有的特征留给你去绘制。图1-4 窗口的非客户区可以由系统选择绘制每个窗口代表内存中的一个窗口对象,并由该窗口对象告诉 Wi n d o w s操作系统将窗口绘制在何处,以及在对鼠标单击、
7、键盘按下(假设该窗口拥有输入焦点)和时钟终止等事件作出响第1章 窗口3下载重叠窗口弹出窗口子窗口注意:在它的最基本的窗体中,系统不进行任何绘制。窗口都是客户区注意:在它的最基本的窗体中,系统不进行任何绘制。窗口都是客户区注意:这都是客户区。子窗口通常自己进行绘制最基本的窗体典型的外观共同的设置注意:子窗口不能有子菜单不是一个窗口显示在子窗口中,并由子窗口绘制属于桌面的重叠窗口,也称为主窗口属于弹出窗口的子窗口,它位于弹出窗口之中属于主窗口的子窗口属于主窗口的弹出窗口水平滚动条垂直滚动条关闭按钮最大化按钮最小化按钮任务栏应用程序图标菜单条系统菜单(单击应用程序图标时,显示虚线框)客户区应时应调用
8、什么应用程序。窗口对象自身是窗口类的一个实例,它不是 Visual C+的类,而是存在于Visual C+之外,并早于Visual C+的Microsoft Wi n d o w s所属的类。然而,就像C+的类一样,窗口类为每个基于它创建的窗口定义了若干特征,如背景色和往何处发送消息等(见图1-5)。图1-5 Microsoft Windows所属的窗口类创建的窗口对象Wi n d o w s操作系统提供了一个扩展的应用程序接口(A P I),可以用来创建和维护这些窗口对象。调用C r e a t e Window()函数可以创建一个窗口对象;调用 S e t WindowLong()函数可以
9、改变由窗口类定义的特征;调用 M o v e Window()函数可以移动窗口;调用D e s t r o y Window()可以退出窗口。如此说来,M F C又能做些什么呢?1.2 窗口和MFC环境M F C窗口是C+和Windows API调用的综合。事实上,M F C窗口提供了许多(但不是全部)Windows API的C+封装,从而减轻了编写 Wi n d o w s应用程序时一些乏味的工作,并提供了一些新的服务。M F C窗口不对窗口对象进行直接控制,而在 A P I环境中却是可以的。如果不能在 A P I环境中实现某项功能,那么肯定也不能在 M F C环境中实现。举例来说,M F
10、C库的C W n d可以创建一个窗口,但它只是过去在A P I环境中使用的A P I调用的封装。微软已经把在 M F C库中创建和维护一个窗口的逻辑作为真正的 C+封装和控制。然而,这种方法虽使得M F C库万能,但却是不方便的,并导致了严重的冗余和更多的错误。创建M F C窗口是复杂的,首先,创建类 C W n d的一个实例,然后调用类 C W n d的一个成员函数,该成员函数调用A P I中的C r e a t Window()函数。返回的窗口句柄(这只是指向窗口对象的非直接指针)保存在类C W n d的成员变量m _ h W n d中。注意 因为窗口在内存中创建,而内存经常发生变化,窗口
11、地址可能是经常变化的。因此,窗口句柄并非直接指向窗口对象,而是指向跟踪窗口对象地址的另一个指针。销毁窗口同样也是复杂的,必须确保销毁了该窗口对象,以及封装该窗口对象的 C W n d实例。虽然C W n d对象知道窗口对象,但是窗口对象并不知道 CWn d对象(见图1-6)。4第一部分 基 础 知 识下载使用RegisterClass()函数创建窗口类窗口对象由CreateWindow()函数创建,作为它的变量传输窗口类窗口管理器保持一个窗口对象列表,并告诉每个对象在屏幕上绘制自己窗口窗口对象窗口类图1-6 应用两个对象创建MFC窗口尽管窗口应用程序的用户界面可以由几十个、甚至几百个窗口构成,
12、但是大多数窗口还是由不到十个的窗口类创建的。即使在应用程序中有一千个窗口,每个窗口也只能是三种基本类型之一:重叠窗口、弹出窗口或子窗口。1.3 怎样应用MFC创建一个窗口可以用M F C的C W n d类创建一个窗口:CWnd wnd;BOOL b=wnd.CreateEx(ExStyle,ClassName,WindowName,Style,x,y,Width,Height,Parent,Menu,P a r a m);第一行代码创建了一个C W n d类的对象,第二行通过调用Windows API函数C r e a t e WindowEx()创建了真正的窗口。HWND h w n d=:
13、C r e a t e WindowEx(ExStyle,ClassName,WindowName,Style,x,y,Width,Height,Parent,Menu,Instance,Param);因为C W n d类只是封装了用于创建窗口的 Windows API函数(C r e a t e WindowEx(),因此,从本质上讲,创建窗口所必须的参数在 A P I环境和M F C环境中是相同的:参数S t y l e和E x S t y l e决定窗口的“外观”和类型(重叠、弹出、子窗口)。参数C l a s s N a m e决定在创建窗口时使用的窗口类。参数Wi n d o w N
14、 a m e决定窗口标题内容(如果窗口标题有内容)。参数x,y,Wi d t h和H e i g h t决定窗口的位置和大小。参数P a r e n t指向拥有该窗口的窗口指针(如果有这样的窗口)。参数M e n u指向内存中的一个对象,作为它的菜单使用除非创建一个子窗口,如果是这样的话,那么该参数是帮助父窗口识别子窗口的 I D n u m b e r。参数I n s t a n c e识别该窗口属于哪个应用程序,以便发送到该窗口的消息能被发送到正确的应用程序的消息队列中。C W n d类填入I n s t a n c e参数。参数P a r a m是在创建窗口时由窗口类使用的指针,该指针是
15、指向附加信息的非强制性结构的指针。返回的h w n d参数是指向创建的窗口对象的指针,但在未创建任何窗口时,该参数返回值为N U L L。窗口句柄自动地保存在C W n d类的m _ h W n d成员变量中,这在前面的图1-6中可以看到。第1章 窗口5下载窗口类调用CWnd的成员函数Create(),该函数自身调用图 1-4中看到的:Create Wi n d o w()函数:Create Window再次创建窗口;窗口句柄保存到CWnd中窗口管理器告知每个窗口对象在屏幕上绘制自己然后,在堆栈上或堆中创建一个CWnd类对象首先,用AfxRegister Class()函数创建一个窗口类窗口窗
16、口对象CWnd类对象现在既然已了解了有关创建窗口的基本知识,那么让我们进一步来看看填写这些参数的规则。规则1.窗口名称参数该参数是一个零结尾的文本串,用该串指明在窗口标题栏中显示的内容。如果窗口没有标题栏,该参数可以为零(0)。然而,某些通用控件也使用该参数。例如,按钮控件把该参数的内容放在按钮的表面。在创建窗口标题栏后,可以用类C W n d的成员函数S e t Wi n d o w Te x t()来改变窗口标题栏的名称。2.风格和扩展风格参数这两个是3 2位的参数,用来指定创建什么类型的窗口。可以选择多种类型,如下面的例子所示:,W S _ C H I L D|W S _ V I S I
17、 B L E,窗口风格参数的作用包括:用于创建三种基本窗口类型的风格,用 W M _ C H I L D创建一个子窗口;用 W M _ P O P U P创建一个弹出窗口。W M _ O V E R L A P P E D创建一个重叠窗口。如果不为窗口指定任何一种风格,那么窗口风格默认为W M _ O V E R L A P P E D。用以增添窗口的非客户区特色的风格。例如,可以用 W S _ V S C R O L L为窗口添加一个垂直滚动条,如图1-7所示其他非客户区窗口风格。图1-7 非客户窗口风格用来增添窗口的特色由每个通用控件定义的风格。例如,B S _ F L AT按钮风格告诉按
18、钮控件绘制一个二维按钮。用来使窗口可视、可操作和/或初始最大化的风格。用来标识控件组起始控件的风格,或者当用户敲击 Ta b键控制焦点在窗口中变化时,用来指示哪个控件有资格获得输入焦点的风格。想了解更多的有关窗口风格的例子,请参阅附录 A。在创建窗口以后,可以用 C W n d的成员函数ModifyStyle()和ModifyStyleEx()改变窗口风格。某些风格可能要求重画窗口,这时,可以给 ModifyStyle()函数添加第三个参数,自动激发类C W n d的成员函数S e t WindowPos()做重画窗口工作。6第一部分 基 础 知 识下载如果选取了最小化或最大化按钮则关闭按钮出
19、现若在CreateWindow()中定义了菜单条,则菜单条出现,它不是一个子窗口(使窗口可视)(禁止窗口输入)CWnd wnd;wnd.ModifyStyle(0,WS_BORDER,SWP_NOZORDER);事实上,给 M o d i f y S t y l e()或M o d i f y S t y l e E x()添加任何第三个参数,都需要添加下面的S e t WindowPos()选项:S W P _ N O Z O R D E R、S W P _ N O M O V E、S W P _ N O A C T I VAT E和S W P _ S H O W。注意 有时候,甚至一个重画
20、的窗口可能与新风格不相容,尤其对通用控件窗口来说更是这样。因为单个窗口决定重画窗口时使用什么风格。在这种情况下,唯一的办法是:在事先存储已有窗口的风格和其他参数后,销毁和重建该窗口。3.X和Y位置参数这是两个3 2位的参数,用于以像素为单位指定窗口的位置。创建重叠窗口和弹出窗口时,X和Y是相对于桌面窗口左上角的位置。而创建子窗口时,X和Y是相对于父窗口客户区的左上角位置。如果把 X和Y参数都设置为C W _ U S E D E FA U LT,那么系统将自动为窗口选定一个位置。系统层叠排列这些新窗口(见图1-8)。图1-8 CW_USEDEFAULT允许系统自动设定窗口位置然而,如果X和Y参数
21、都设置为C W _ U S E D E FA U LT,那么子窗口在创建的时候,总被创建在(0,0)的位置。创建窗口以后,可以用类C W n d的成员函数M o v e Window()移动窗口。4.宽度和高度参数这是两个3 2位的参数,用于以像素为单位指定窗口的大小。如果将参数 Wi d t h和H e i g h t都设置为C W _ U S E D E FA U LT,则系统将根据桌面窗口的大小,自动选定窗口的大小。然而,对于一个子窗口来说,系统将创建一个长和宽均为 0的窗口。如果窗口的风格是 W S _ M I N I M I Z E或W S _ M A X I M I Z E,那么系
22、统将忽视用户为Wi d t h和H e i g h t设置的任何值。创建窗口以后,可以用类CWn d的成员函数M o v e Window()重新设置窗口的大小。5.Z-Order当几个窗口占据屏幕上同一区域时,Z-O r d e r决定哪个窗口显示在哪个窗口之上。Z-O r d e r(Z顺序)中的Z来源于坐标X-Y-Z轴的Z轴,其中Z轴垂直屏幕,并由屏幕指向外面。当窗口最初被创建或选中时,则窗口将出现在 Z-O r d e r的顶层。然而,该窗口永远不可能出现在一个最顶层窗口的上面,除非该窗口也是最顶层的窗口。“最顶层”窗口用 W S _ E X _ TO P M O S T窗口风格创建,
23、并显示在所有非最顶层窗口的上面,而与该窗口是不是当前选中的窗口无关。创建窗口后,可以用CWn d的成员函数S e t Wi n d o w P o s()改变窗口的Z顺序。6.父窗口或物主窗口参数该参数是指向类 CWn d对象的指针,根据创建的窗口类型标识是父窗口还是物主窗口第1章 窗口7下载第一窗口下一个窗口第三个窗口(O w n e r):如果创建的是一个子窗口,那么用该参数来标识它的父窗口(该子窗口所放置的并为之所截断的窗口)。该值不能为N U L L。子窗口只能出现在它的父窗口里面,当父窗口被销毁时它们也被销毁,并且当父窗口被隐藏或最小化时它们也被隐藏。如果创建的是重叠窗口或弹出窗口,
24、用该参数来标识物主窗口。如果该值为N U L L,则桌面窗口成为物主窗口。从属窗口总是显示在它们的主窗口上面,并且随着物主窗口的销毁而被销毁;物主窗口最小化时,则从属窗口被隐藏;但当物主窗口被隐藏时,从属窗口并不被隐藏。一个子窗口可能是另一个子窗口的父窗口,但绝不可能是一个物主窗口。如果试图使一个子窗口成为一个物主窗口,那么系统只能使那个子窗口的最顶层窗口作为物主窗口。图 1-9是这些关系的概述。图1-9 物主、父、子窗口的层次关系可以用C W n d的成员函数 SetOwner()改变已有窗口的物主窗口,用 C W n d的成员函数SetParent()改变父窗口。7.菜单或控件I D参数该
25、参数用来标识菜单(M e n u)句柄或控件(Control)ID,这要依赖于创建的窗口是子窗口、重叠窗口,还是弹出窗口。如果创建的是一个子窗口,用该参数标识控件 I D,控件I D通常用来帮助父窗口识别子窗口。因为该参数寻求一个 H M E N U变量,因此,需要用H M E N U类型重载变量定义控件I D。例如,如果子窗口的控件I D是1 0 2,应该用如下方法定义它:,(HMENU)102,如果创建的是一个重叠窗口或弹出窗口,用该参数定义窗口的菜单。若该值为 N U L L,则菜单默认为在该窗口的窗口类中定义的任何菜单;如果窗口类也没有指定的菜单,则该窗口在创建时没有菜单。可以用下面的
26、方法为该参数加载一个菜单:HMENU hMenu=:LoadMenu(AfxGetInstanceHandle(),MAKEINTRESOURCE(xx);8第一部分 基 础 知 识下载子窗口对象被创建,并显示在父窗口中重叠或弹出窗口对象被创建,并显示在屏幕上 弹出或重叠窗口对象被创建,并显示在父窗口中这里的x x是应用程序资源里面的菜单ID(Menu ID)。可以用C W n d的SetDlgCtrlID()改变已有子窗口的I D。用类C W n d的成员函数SetMenu()改变一个重叠窗口或弹出窗口的菜单。8.实例前面已提到,C W n d类将填入该参数。C W n d通过调用AfxGe
27、tInstanceHandle()获得该实例(I n s t a n c e)。一个应用程序的实例从本质上标识了哪个程序在内存里。AfxGetInstanceHandle()是由M F C库提供的静态函数。9.参数该3 2位参数(P a r a m e t e r)是可选的。它通常是指向一个结构或者类对象的指针,而该结构或者类对象是创建某种类型的窗口时需要提供的。例如,当用M D I C L I E N T窗口类创建窗口时,需要该参数提供一个C L I E N T C R E AT E S T R U C T结构的指针。10.类名参数类名(Class Name)参数是一个零结尾字符串,当创建一
28、个窗口时,用来标识使用那个窗口类。关于窗口类和窗口处理,将在本章后面的内容中详细讨论。该参数不能为 N U L L,在创建一个非常一般的M F C窗口时,使用AfxRegisterWndClass(0)填入该参数。1.4 怎样使用MFC销毁一个窗口如前面所提到的一样,删除一个 M F C窗口可能有些烦琐,必须按下面的顺序删除两个对象:p W n d-D e s t r o y Window();/destroys Window Objectdelete pWnd;/destroys Cwnd Object也可以只删除C W n d对象,因为D e s t r o y Window()是从C W
29、 n d的析构函数中调用的,但不提倡使用这种方法。销毁一个窗口而不先调用 D e s t r o y Window()函数,将使某些析构消息不能被任何从C W n d派生的类处理。你几乎不需自己销毁一个窗口,用户或系统通常会做这项工作。如果需要在销毁窗口的同时销毁 C W n d对象,则应该在 C W n d的派生类中添加下面的重载函数:C YourWnd:PostNcDestroy()delete this;PostNcDestroy()是销毁窗口前调用的最后一个成员函数。但是,几乎不需对该函数进行重载,因为C W n d和派生类一般是嵌在另一个类中或建立在堆栈中的。1.4.1 捆绑到一个已
30、有的窗口如果一个窗口是用Windows API在应用程序建立之前或外面创建的,并且需要把它封装到C W n d类中,可以用下面的语句实现:CWnd wnd;wnd.Attach(hwnd);这里的h w n d是已有窗口的句柄。Attach()只是把C W n d的成员变量m _ h W n d赋给h w n d。也可以使用CWnd:FromHandle(hwnd),它查看是否有C W n d对象已经封装了该窗口句柄并返回该C W n d对象的指针。如果不存在这样的 C W n d对象,将创建一个临时对象。如果是临第1章 窗口9下载时对象,则不要使用该指针,因为在应用程序空闲的时候,该指针指向
31、的对象将被删除。1.4.2 窗口类前面已提及,一个窗口类不是一个 C+类,而是早于并存在于 C+之外的窗口专有的类。窗口类的作用就像一个模板,可以由此创建其他窗口,并可共享某些特征,包括下面所示的特征:类风格包括能给予窗口的一些微小的特征。类图标如果窗口有图标,用它来指定在窗口的左上角处所画的图标。类菜单如果窗口有菜单,用它来指定窗口中显示的菜单。类光标当光标通过窗口的客户区时,用它来指定显示哪种鼠标形状。背景色定义用什么颜色来擦除窗口的背景色。窗口的客户区将显示该颜色。窗口进程定义处理任何发送到该窗口的消息时应该调用的函数。定义窗口进程可能是窗口类唯一最重要的前提。1.4.3 窗口进程窗口与
32、环境的交互是通过发送和接收消息来实现的。如果系统要求窗口自己进行绘制,系 统给 它发送 一个 W M _ PA I N T 消 息;如果系 统要 求窗口 销毁 自己,则发 送一个W M _ D E S T R O Y消息。这些消息都由窗口的窗口进程处理,该窗口进程的地址在窗口类中定义。对于发送到由相同的窗口类创建的窗口的消息,系统采用完全相同的窗口进程进行处理。相同的窗口进程是怎样跟踪所有的窗口的呢?它是怎么知道窗口 A画在(1 0,3 4),而窗口B画在(5 6,2 1)呢?所有这些工作的完成只需使用窗口的窗口对象。例如,所有用按钮窗口类创建的窗口,都使用相同的按钮窗口进程。如果一个W M
33、_ PA I N T消息发送到其中任何一个窗口,则按钮窗口进程根据每个窗口的窗口对象指定的大小、位置和风格画出确切的按钮(见图1-1 0)。图1-10 按钮窗口进程使用窗口对象指定对哪个窗口进行操纵10第一部分 基 础 知 识下载 窗口进程也搜索窗口对象以查明在哪里绘制这些控件窗口如果风格是“PushButton”,则窗口进程绘制一个按钮通过发送一个W M _ PA I N T 消息到窗口进程,窗口管理器告诉每个窗口绘制自己用“BUTTON”窗口类创建的窗口“BUTTON”的窗口进程搜索窗口对象,以查明绘制什么类型的按钮,如果风格是“Check Box”,则绘制一个复选框父窗口窗口对象1.5
34、怎样使用MFC创建一个窗口类当用户创建一个窗口类时,实际上只是在三个操作系统列表之一中注册一个 W N D C L A S S结构。系统为每个窗口类类型维护一个列表:系统全局类(System Global Class)在系统启动时注册,且必须注册,对所有应用程序都有效。应用程序全局类(Application Global Class)由应用程序注册,只对应用程序及应用程序的线程有效。应用程序局部类(Application Local Class)由应用程序注册,并只对注册它们的应用程序或D L L有效。当系统搜索一个窗口类时,从应用程序局部类开始,然后搜索应用程序全局类,最后搜索系统全局类。要
35、创建一个窗口类,可以先创建 W N D C L A S S结构的实例,然后用M F C类库的A f x R e g i s t e rClass()注册它。也可以用 M F C类库的AfxRegisterWndClass()来创建一个基于调用参数的W N D C L A S S对象。1.5.1 使用AfxRegisterWndClass()函数注册一个窗口类AfxRegisterWndClass()函数在使用上是非常自动化的,一些通常需要你提供的参数都能自己填入,甚至连新的窗口类的名字也能自动产生。LPCTSTR lpszClassName=AfxRegisterWndClass(UINT n
36、ClassStyle,HCURSOR hCursor=0,HBRUSHhbrBackground=0,HICON hIcon=0);这些参数的使用规则如下:1.类名根据传给该函数的参数,为新的窗口类产生名字。如果传输的参数完全相同,那么创建的窗口类也将完全相同。如果需要创建新的窗口类,可以用 AfxRegisterClass()。2.风格窗口类风格由下面选项列表中一系列标记的或(O R)运算提供:类风格描述C S _ O W N D C为为该窗口类创建的每个窗口分配唯一的设备环境。有关设备环境的更详尽资料见第4章CS_ PA R E N T D C为从系统高速缓存中检索设备环境,然后设置该设备
37、环境的剪裁区,以组合到父窗口中,以便子窗口能画在父窗口上C S _ C L A S S D C为分配一个设备环境给所有由该窗口类创建的窗口使用C S _ S AV E B I T S为由该类创建的任何窗口的视频存储区将被保存,以便窗口移动或关闭时,不需要重画基础窗口这对快速机器来说作用不大C S _ B Y T E A L I G N C L I E N T为当计算机的显示卡和C P U速度较慢时,这两种风格有用。添加这些风格后,当C S _ B Y T E A L I G N W I N D O W窗口在字节边缘时,显示卡更容易移动窗口C S _ G L O B A L C L A S S为
38、如果设置该风格,则该类是应用程序的全局类,否则它是一个应用程序局部类C S _ V R E D R AW为如果设置了垂直风格,并且窗口的垂直大小发生了变化,则整个窗口被重画。C S _ H R E D R AW水平风格也这样C S _ N O C L O S E为禁用系统菜单中的关闭命令C S _ D B L C L K S为如果未设置该参数,并且双击由该窗口类创建的窗口,则传送给应用程序的将不是双击事件,而是两个相继完成的单击事件第1章 窗口11下载3.图标(I c o n)该参数是显示在窗口左上角的图标的句柄,但只适用于使用 W S _ S Y S M E N U的窗口风格。应用程序主窗口
39、的图标也显示在任务栏上。如果将该参数设置为N U L L,并且设置了W S _ S Y S M E N U风格,则系统将提供一个默认的图标。在 M F C环境中,绝大部分图标已被处理过,用CWn d的S e t I c o n()可改变已有的图标。4.光标(C u r s o r)该参数是鼠标移经应用程序窗口的客户区时,将要显示的鼠标光标句柄。如果将该参数设置为N U L L,则显示的是箭头光标。可以用下面的语句装载一个光标:HICON hIcon=AfxGetApp()-LoadCursor(xx);这里的x x是应用程序资源中光标的名字或I D。这里指定的光标意味着是该窗口的默认光标。如果
40、想动态地改变光标形状,则应该处理该窗口的W M _ S E T C U R S O R消息,并用SetCursor()来改变光标形状(见第8章例3 3)。5.背景色当系统创建窗口时,先在显示窗口的地方画一个矩形区域,以擦除该区域的背景色。该参数指定填充该矩形域时所用画刷的句柄(参见第4章有关画刷的详细内容)。为窗口类创建的画刷对象在该类退出注册时被自动释放。在指定背景色时,也可以不创建画刷对象,而指定下面所列系统颜色之一:C O L O R _ A C T I V E B O R D E RC O L O R _ A C T I V E C A P T I O NC O L O R _ A P
41、 P W O R K S PA C EC O L O R _ B A C K G R O U N DC O L O R _ B T N FA C EC O L O R _ B T N S H A D O WC O L O R _ B T N T E X TC O L O R _ C A P T I O N T E X TC O L O R _ G R AY T E X TC O L O R _ H I G H L I G H TC O L O R _ H I G H L I G H T T E X TC O L O R _ I N A C T I V E B O R D E RC O L O
42、R _ I N A C T I V E C A P T I O NC O L O R _ M E N UC O L O R _ M E N U T E X TC O L O R _ S C R O L L B A RC O L O R _ W I N D O WC O L O R _ W I N D O W F R A M EC O L O R _ W I N D O W T E X T然而,必须分配颜色到一个画刷句柄类型,并加 1。(HBRUSH)(COLOR_WINDOW+1)设置该参数为N U L L,则在画一个窗口之前,系统不对窗口进行擦除。在非客户区的绘制还是同平常一样,但客户区将保
43、持窗口被画前原来屏幕所显示的样子。若该参数设为 N U L L,应确认窗口是画全部客户区,还是处理 W M _ E R A S E B R G N D消息以擦除背景颜色。1.5.2 使用AfxRegisterClass()函数创建一个窗口类如果想完全控制一个新窗口类的创建,如指定窗口类的名字,则应该用下面的语句:12第一部分 基 础 知 识下载BOOL AFXAPI AfxRegisterClass(WNDCLASS lpWndClass);这里的W N D C L A S S结构定义如下:typedef struct _WNDCLASS UINT style;/style of the cl
44、assW N D P R O Cl p f n W n d P r o c;/function called by system when/it has a message for a window/created with this classi n tc b C l s E x t r a;/extra bytes to add to the/WNDCLASS structure when/registeringi n tc b W n d E x t r a;/extra bytes to add to the Wi n d o w/Objects created with this c
45、lassH A N D L Eh I n s t a n c e;/instance that owns this classH I C O Nh I c o n;/icon to be used when window/displays an iconH C U R S O Rh C u r s o r;/cursor to use when mouse is over/a window created with this classH B R U S Hh b r B a c k g r o u n d;/background color to use when/erasing the b
46、ackground area under/a window created with this classL P C T S T Rl p s z M e n u N a m e;/menu name to be used when/creating a menu for a window/created with this classL P C T S T Rl p s z C l a s s N a m e;/the class name that identifies/this WNDCLASS for the system WNDCLASS;有关填入类的“风格”、“图标”、“光标”和“
47、背景色”参数的规则参看前面部分的介绍,其余参数的填入规则如下:1.类名类名参数是用来标识新窗口类的零结尾字符串。可以任意命名窗口类,但是不要与已有的窗口类同名,除非想使该类无效。正如前面所提及的,系统从应用程序局部类开始,在三个列表中寻找类名匹配,如果在该列表中记录了一个与系统全局类同名的类,则应用程序将使用新记录的类。2.菜单名该参数指向应用程序资源中的菜单名。在 M F C环境中,大多数情况下由系统载入菜单,但可以在此处指定菜单名。如果使用资源 I D,也可以采用下面语句:MAKEINTRESOURCE(IDR_MENU);这将成为该窗口的默认菜单。若指定该值为 N U L L,系统将使用
48、在类C W n d的CreateEx()中定义的菜单;若在此处没有指定的菜单,该窗口将没有菜单。该参数对子窗口可以忽略,因为它们从来没有菜单。3.窗口进程和实例这两个参数是窗口类中最重要的参数。有关窗口进程在前面已经讨论过了,而实例只是第1章 窗口13下载用以标识哪个应用程序包含了该窗口进程。在M F C环境中,默认的窗口进程为AfxWndProc(),可以使用下面语句返回该进程,并为该参数使用。AfxGetAfxWndProc();可以用AfxGetInstanceHandle()填入I n s t a n c e参数。4.Class Extra和Window Extra参数C l a s
49、s E x t r a和Wi n d o w E x t r a参数提供了一种存储数据的方法,允许应用程序自身将所属的数据存储到窗口对象或注册的窗口类中。注册类时,Class Extra指定在类的末尾分配的额外字节数;创建窗口对象时,Window Extra指定添加到该窗口对象尾部的额外字节数。在这两种情况下,这些额外字节都被应用程序用来存储属于窗口或窗口类的消息。然而,由于C W n d对象与一个窗口关联,并且一个 C W n d对象可以存储的信息量若不比额外字节多的话,起码也与之相等;因此,这些额外字节参数实际上并没有多大用处,可以把它们设为 0。1.6 怎样销毁一个MFC窗口类通过取消窗
50、口类的注册销毁窗口类。但是,如果用 AfxRegisterWnd()或A f x R e g i s t e r W n d-Class()注册一个类的话,那么在应用程序结束的时候,类的注册会自动取消,即使应用程序不取消窗口类的注册,操作系统也会取消。1.7 厂商安装的窗口类应用程序可能运行在一个已注册若干个窗口类的环境中。其中的一些是由操作系统(Windows 3.1/95/98/NT)提供的;另一些是由M F C提供的。由系统提供的控件窗口也叫做通用控件。1.一些重要的窗口类Windows 3.1及以上版本:类创建的窗口类创建的窗口#3 2 7 6 8弹出式菜单窗口(弹出式菜#3 2 7