资源说明:VISUAL_C++MFC编程实例用Visual C++ 和M F C创建的应用程序大多会自动生成窗口,并且可以处理消息,
进行绘图。M i c r o s o f t在这方面做了大量的工作,隐藏了内部工作,使我们能够更轻松
地创建一个一般的应用程序。然而,当用户不能实现他们想要实现的功能时,适当地
了解内部工作机制,对于消除编程上的困惑会有好处。更重要的是,知道怎样执行任
务(诸如把窗口放置到什么地方,从什么地方获得一个消息和在任意地方绘图),有助
于分清用户的应用程序和由Visual C++ 和M F C自动提供的限于窗口、消息和绘图的应
用程序。
Visual C++应用程序有四项主要基本知识:创建一个窗口、了解其他的M F C类、把消息
发送到一个窗口和在一个窗口内绘图。当然还有其他一些基本知识,我们也将在涉及时适当
地进行讨论。不过本部分将讨论以下四项基本知识。
窗口在第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 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章窗口
在本章中,我们将讨论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 )窗口和子窗口
( C h i l d )。在它们之间并没有太多内在的差异,但是使用不同的窗口风格,它们的外观是不同
的(见图1 - 2 )。
重叠窗口通常用于建立应用程序主窗口。事实上,有时也叫做“主”窗口或者“框架”
窗口。
弹出窗口通常以对话框和消息框的形式与用户对话。
子窗口通常用在视图( Vi e w )中,如在文本编辑器中的文本显示,也用在控件中,如在对
话框中的O K按钮。而对那些看起来像按钮或控件的子窗口,也称为“控件”窗口。
重叠窗口和弹出窗口的主要区别是弹出窗口出现时可以没有标题(也称为标题栏)。子窗口
与重叠窗口或弹出窗口的主要区别是子窗口只能出现在另一个窗口中,并且子窗口的任何多
余部分都被该窗口移去或剪切掉。另外,子窗口是唯一不能有菜单条的窗口。
参见图1 - 3中的Windows 应用程序,其中包括重叠窗口、弹出窗口和子窗口。
应用程序的主窗口
窗口
窗口
窗口
窗口
图1-2 窗口风格可以用来区分三种不同类型的窗口
图1-3 由重叠窗口、弹出窗口和子窗口组成的窗口应用程序
1.1.2 客户区和非客户区
每个窗口都有由系统绘制的“非客户区”和由应用程序绘制的“客户区”。系统可以绘制
图1 - 4显示的其中一个或者全部特征,当然也可以把所有的特征留给你去绘制。
图1-4 窗口的非客户区可以由系统选择绘制
每个窗口代表内存中的一个窗口对象,并由该窗口对象告诉Wi n d o w s操作系统将窗口绘
制在何处,以及在对鼠标单击、键盘按下(假设该窗口拥有输入焦点)和时钟终止等事件作出响
第1章窗口3
下载
重叠窗口弹出窗口子窗口
注意:在它的最基
本的窗体中,系统
不进行任何绘制。
窗口都是客户区
注意:在它的最基
本的窗体中,系统
不进行任何绘制。
窗口都是客户区
注意:这都是客户区。子
窗口通常自己进行绘制
最基本的
窗体
典型的外观
共同的设置
注意:子窗口不能有子菜单
不是一个窗口—
显示在子窗口中,
并由子窗口绘制
属于桌面的重叠窗
口,也称为主窗口
属于弹出窗口的子
窗口,它位于弹出
窗口之中
属于主窗口的子窗口
属于主窗口的弹
出窗口
水平滚动条
垂直滚动条
关闭按钮
最大化按钮
任务栏 最小化按钮
应用程序图标
菜单条
系统菜单(单击应用程
序图标时,显示虚线框)
客户区
应时应调用什么应用程序。窗口对象自身是窗口类的一个实例,它不是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( )函数可以改
变由窗口类定义的特征;调用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 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中。
注意因为窗口在内存中创建,而内存经常发生变化,窗口地址可能是经常变化的。因
此,窗口句柄并非直接指向窗口对象,而是指向跟踪窗口对象地址的另一个指针。
销毁窗口同样也是复杂的,必须确保销毁了该窗口对象,以及封装该窗口对象的C W n d实
例。虽然C W n d对象知道窗口对象,但是窗口对象并不知道CWn d对象(见图1 - 6 )。
4 第一部分基础知识
下载
①使用RegisterClass( )
函数创建窗口类②窗口对象由CreateWindow( )
函数创建,作为它的变量传
输窗口类
③窗口管理器保持一个窗口对
象列表,并告诉每个对象在
屏幕上绘制自己
窗口
窗口对象
窗口类
图1-6 应用两个对象创建MFC窗口
尽管窗口应用程序的用户界面可以由几十个、甚至几百个窗口构成,但是大多数窗口还
是由不到十个的窗口类创建的。即使在应用程序中有一千个窗口,每个窗口也只能是三种基
本类型之一:重叠窗口、弹出窗口或子窗口。
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 = : : 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 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是在创建窗口时由窗口类使用的指针,该指针是指向附加信息的非强制性结
构的指针。
返回的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( )
函数创建一个窗口类
窗口
窗口对象
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 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按钮风格告诉按钮控件绘制一个二维按
钮。
■ 用来使窗口可视、可操作和/或初始最大化的风格。
■ 用来标识控件组起始控件的风格,或者当用户敲击Ta b键控制焦点在窗口中变化时,用
来指示哪个控件有资格获得输入焦点的风格。
■ 想了解更多的有关窗口风格的例子,请参阅附录A。
在创建窗口以后,可以用C W n d的成员函数ModifyStyle( )和ModifyStyleEx( )改变窗口风
格。某些风格可能要求重画窗口,这时,可以给ModifyStyle( )函数添加第三个参数,自动激
发类C W n d的成员函数S e t WindowPos( )做重画窗口工作。
6 第一部分基础知识
下载
如果选取了最小化或最大化按
钮则关闭按钮出现
若在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。
注意有时候,甚至一个重画的窗口可能与新风格不相容,尤其对通用控件窗口来说更
是这样。因为单个窗口决定重画窗口时使用什么风格。在这种情况下,唯一的办法是:
在事先存储已有窗口的风格和其他参数后,销毁和重建该窗口。
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参数都设置为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,那么系统将忽视用户为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
窗口风格创建,并显示在所有非最顶层窗口的上面,而与该窗口是不是当前选中的窗口无关。
创建窗口后,可以用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。子窗口只能出现在它的父窗口里面,当父窗口被
销毁时它们也被销毁,并且当父窗口被隐藏或最小化时它们也被隐藏。
■ 如果创建的是重叠窗口或弹出窗口,用该参数来标识物主窗口。如果该值为N U L L,
则桌面窗口成为物主窗口。从属窗口总是显示在它们的主窗口上面,并且随着物主窗
口的销毁而被销毁;物主窗口最小化时,则从属窗口被隐藏;但当物主窗口被隐藏时,
从属窗口并不被隐藏。
一个子窗口可能是另一个子窗口的父窗口,但绝不可能是一个物主窗口。如果试图使一
个子窗口成为一个物主窗口,那么系统只能使那个子窗口的最顶层窗口作为物主窗口。图1 - 9
是这些关系的概述。
图1-9 物主、父、子窗口的层次关系
可以用C W n d的成员函数SetOwner( ) 改变已有窗口的物主窗口,用C W n d的成员函数
SetParent( )改变父窗口。
7. 菜单或控件I D参数
该参数用来标识菜单( 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,
则菜单默认为在该窗口的窗口类中定义的任何菜单;如果窗口类也没有指定的菜单,
则该窗口在创建时没有菜单。可以用下面的方法为该参数加载一个菜单:
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通过调用AfxGetInstanceHandle( )获得该实例
( 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)参数是一个零结尾字符串,当创建一个窗口时,用来标识使用那个窗口
类。关于窗口类和窗口处理,将在本章后面的内容中详细讨论。该参数不能为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 Object
delete pWnd; //destroys Cwnd Object
也可以只删除C W n d对象,因为D e s t r o y Window( )是从C W 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 捆绑到一个已有的窗口
如果一个窗口是用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
下载
时对象,则不要使用该指针,因为在应用程序空闲的时候,该指针指向的对象将被删除。
1.4.2 窗口类
前面已提及,一个窗口类不是一个C + +类,而是早于并存在于C + +之外的窗口专有的类。
窗口类的作用就像一个模板,可以由此创建其他窗口,并可共享某些特征,包括下面所示的
特征:
类风格包括能给予窗口的一些微小的特征。
类图标如果窗口有图标,用它来指定在窗口的左上角处所画的图标。
类菜单如果窗口有菜单,用它来指定窗口中显示的菜单。
类光标当光标通过窗口的客户区时,用它来指定显示哪种鼠标形状。
背景色定义用什么颜色来擦除窗口的背景色。窗口的客户区将显示该颜色。
窗口进程定义处理任何发送到该窗口的消息时应该调用的函数。定义窗口进程可能是窗
口类唯一最重要的前提。
1.4.3 窗口进程
窗口与环境的交互是通过发送和接收消息来实现的。如果系统要求窗口自己进行绘制,
系统给它发送一个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 PA I N T消息发送到其中任何一个窗口,则按钮窗口进程根据每个窗口的窗口对象指定的
大小、位置和风格画出确切的按钮(见图1 - 1 0 )。
图1-10 按钮窗口进程使用窗口对象指定对哪个窗口进行操纵
10 第一部分基础知识
下载
⑤ 窗口进程也搜索窗口对象以
查明在哪里绘制这些控件窗
口
④如果风格是“ Push
Button”,则窗口进
程绘制一个按钮
②通过发送一个W M _ PA I N T 消
息到窗口进程,窗口管理器
告诉每个窗口绘制自己
①用“BUTTON”窗
口类创建的窗口
③“ BUTTON”的窗口进程搜索窗口对象,以
查明绘制什么类型的按钮,如果风格是
“Check Box”,则绘制一个复选框
父窗口
窗口对象
1.5 怎样使用MFC创建一个窗口类
当用户创建一个窗口类时,实际上只是在三个操作系统列表之一中注册一个W N D C L A S S
结构。系统为每个窗口类类型维护一个列表:
系统全局类(System Global Class) 在系统启动时注册,且必须注册,对所有应用程序都
有效。
应用程序全局类(Application Global Class) 由应用程序注册,只对应用程序及应用程序
的线程有效。
应用程序局部类(Application Local Class) 由应用程序注册,并只对注册它们的应用程序
或D L L有效。
当系统搜索一个窗口类时,从应用程序局部类开始,然后搜索应用程序全局类,最后搜
索系统全局类。
要创建一个窗口类,可以先创建W N D C L A S S结构的实例,然后用M F C类库的A f x R e g i s t e r
Class( ) 注册它。也可以用M F C类库的AfxRegisterWndClass( ) 来创建一个基于调用参数的
W N D C L A S S对象。
1.5.1 使用AfxRegisterWndClass( )函数注册一个窗口类
AfxRegisterWndClass( )函数在使用上是非常自动化的,一些通常需要你提供的参数都能
自己填入,甚至连新的窗口类的名字也能自动产生。
LPCTSTR lpszClassName=AfxRegisterWndClass(UINT nClassStyle, HCURSOR hCursor=0,HBRUSH
hbrBackground=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 为从系统高速缓存中检索设备环境,然后设置该设备环境的剪裁区,以组合到父
窗口中,以便子窗口能画在父窗口上
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 为如果设置该风格,则该类是应用程序的全局类,否则它是一个应用程序局部类
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的窗口风格。
应用程序主窗口的图标也显示在任务栏上。如果将该参数设置为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。
这里指定的光标意味着是该窗口的默认光标。如果想动态地改变光标形状,则应该处理
该窗口的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 R
C O L O R A C T I V E C A P T I O N
C O L O R A P P W O R K S PA C E
C O L O R B A C K G R O U N D
C O L O R B T N FA C E
C O L O R B T N S H A D O W
C O L O R B T N T E X T
C O L O R C A P T I O N T E X T
C O L O R G R AY T E X T
C O L O R H I G H L I G H T
C O L O R H I G H L I G H T T E X T
C O L O R I N A C T I V E B O R D E R
C O L O R I N A C T I V E C A P T I O N
C O L O R M E N U
C O L O R M E N U T E X T
C O L O R S C R O L L B A R
C O L O R W I N D O W
C O L O R W I N D O W F R A M E
C O L O R W I N D O W T E X T
然而,必须分配颜色到一个画刷句柄类型,并加1。
(HBRUSH) (COLOR_WINDOW+1)
设置该参数为N U L L,则在画一个窗口之前,系统不对窗口进行擦除。在非客户区的绘制
还是同平常一样,但客户区将保持窗口被画前原来屏幕所显示的样子。若该参数设为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 class
W N D P R O C l 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 class
i n t c b C l s E x t r a ; // extra bytes to add to the
// WNDCLASS structure when
// registering
i n t c b W n d E x t r a ; // extra bytes to add to the Wi n d o w
// Objects created with this class
H A N D L E h I n s t a n c e ; // instance that owns this class
H I C O N h I c o n ; //icon to be used when window
// displays an icon
H C U R S O R h C u r s o r ; // cursor to use when mouse is over
// a window created with this class
H B R U S H h b r B a c k g r o u n d ; // background color to use when
// erasing the background area under
// a window created with this class
L P C T S T R l 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 class
L P C T S T R l p s z C l a s s N a m e ; // the class name that identifies
// this WNDCLASS for the system
} WNDCLASS;
有关填入类的“风格”、“图标”、“光标”和“背景色”参数的规则参看前面部分的介绍,
其余参数的填入规则如下:
1. 类名
类名参数是用来标识新窗口类的零结尾字符串。可以任意命名窗口类,但是不要与已有
的窗口类同名,除非想使该类无效。正如前面所提及的,系统从应用程序局部类开始,在三
个列表中寻找类名匹配,如果在该列表中记录了一个与系统全局类同名的类,则应用程序将
使用新记录的类。
2. 菜单名
该参数指向应用程序资源中的菜单名。在M F C环境中,大多数情况下由系统载入菜单,
但可以在此处指定菜单名。如果使用资源I D,也可以采用下面语句:
MAKEINTRESOURCE (IDR_MENU);
这将成为该窗口的默认菜单。若指定该值为N U L L,系统将使用在类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 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窗口类
通过取消窗口类的注册销毁窗口类。但是,如果用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 7 0 对话框
单是位于弹出窗口中,并
完全填充弹出窗口的菜单)
# 3 2 7 6 9 桌面窗口M D I C l i e n t M D I子窗口区域
2. 一些重要的通用控件窗口类
Windows 3.1及以上版本:
类创建的窗口类创建的窗口
B U T TO N 按钮控件窗口S C R O L L B A R 滚滚动条控件窗口
S TAT I C 静态控件窗口C O M B O B O X 滚组合框控件窗口
E D I T 编辑控件窗口C o m b o L B o x 滚列表框控件窗口(显示在组
L I S T B O X 列表框控件窗口合框控件窗口之下的列表框)
3. 一些重要的通用控件窗口类
Windows 95/NT及以上版本:
14 第一部分基础知识
下载
类创建的窗口类创建的窗口
R I C H E D I T 滚多信息编辑控件窗口; S y s Ta b C o n t r o l 3 2 选项卡控件窗口
S y s L i s t Vi e w 3 2 滚列表视图控件窗口S y s M o n t h C a l 3 2 月历控件窗口
C o m b o B o x E x 3 2 滚扩展组合框控件窗口S y s D a t e Ti m e P i c k 3 2 日期/时间选项控件窗口
S y s A n i m a t e 3 2 滚动画控件窗口m s c t l s h o t k e y 3 2 热键控件窗口
m s c t l s t r a c k b a r 3 2 滚幻灯片控件窗口t o o l t i p s c l a s s 3 2 工具提示控件窗口
S y s Tr e e Vi e w 3 2 滚树型视图控件窗口m s c t l s s t a t u s b a r 3 2 状态栏窗口
m s c t l s u p d o w n 3 2 滚微调按钮控件窗口t o o l b a r Wi n d o w 3 2 工具栏窗口
m s c t l s p r o g r e s s 3 2 滚进度指示控件窗口R e B a r Wi n d o w 3 2 R e b a r窗口
S y s H e a d e r 3 2 滚标题控件窗口(标题控件通
常驻留在列表视图控件的顶
部)
4. 一些重要的M F C窗口类
类创建的窗口类创建的窗口
A f x W n d C W n d窗口A f x M D I F r a m e M D I框架窗口
A f x F r a m e O r Vi e w M F C框架和视窗A f x C o n t r o l B a r M F C控制条窗口
1.8 其他类型窗口
窗口有三种基本的类型—重叠窗口、弹出窗口和子窗口。但在一个M F C应用程序中,
可以用不同的方法使用它们。除非特别提到,封装这些窗口的类都从CWn d类派生。下面列出
的是从使用角度分类的窗口类型:
控件窗口完全把自己画得像个控件的子窗口。例如按钮、静态文本控件和列表框等。
对话框一个弹出窗口,使用资源文件中指定的控件填充自己,并对控件作出处理。
消息框应用程序用来提示用户作出反应的弹出窗口。
工具栏绘制自身按钮的子窗口。
对话条保持打开状态,作为工具栏的对话框。
状态栏一个子窗口,通常位于应用程序主窗口的底部,并用来显示正在使用的命令的帮
助信息。
框架窗口一个重叠窗口,通常在应用程序中作为所有其他窗口的父窗口和物主窗口。框
架窗口也可以通过应用程序对象监督用户命令,这一问题将在下一章中进行详细讨论。
文档/视图实际上是由两个M F C类对象和一个子窗口构成的。M F C应用程序是以“文档
为中心的”,这意味着应用程序负责装载、查看、编辑和存储文档,而不管这些文档是文本文
件、图形文件还是二进制结构文件。首先,创建M F C文档类对象,从磁盘中读入一个文档,
赋予其成员变量;然后,创建一个或多个视图类对象,以显示这些成员变量。如果创建了多
个视图类对象,则一个文档将有多个视图。由于M F C文档类没有关联窗口,因而它不是从
C W n d类派生的。
文档模板实际上没有窗口,而是在打开一个文档时,应用程序用来确定创建什么样的
M F C文档类对象和M F C视图对象。理论上讲,一个应用程序可以有多个文档模板,并允许一
个应用程序处理多种类型的文档,然而,绝大多数应用程序只有一个模板。M F C文档模板不
第1章窗口15
下载
是从C W n d类派生的。想更多地了解有关文档模板的内容,请参看第2章。
1.9 桌面窗口
本章中最后一个问题是桌面窗口(Desktop Wi n d o w ),所有其他窗口都显示在它的上面,
并最终属于它。桌面窗口自身是一个弹出窗口,并且是最高阶弹出窗口。最高阶窗口列表是
由窗口管理器维护的,因此也叫做窗口管理器列表( Windows Manager List)。窗口管理器应用
该列表维护桌面窗口,如图1 - 11所示:
图1-11 窗口管理器通过使用窗口管理器列表维护桌面窗口
桌面窗口的其他相关信息如下:
■ 桌面窗口由# 3 2 7 6 9窗口类所建(不是数字“ 3 2 7 6 9”,而是字符串# 3 2 7 6 9 )。
■ 若要获得桌面窗口的句柄,可以用: : G e t D e s k t o p Window( )。
■ 可以用带S P I S E T D E S K WA L L PA P E R参数的SystemParametersInfo( )在桌面上设置一幅
背景图像。
■ Shell_NotifyIcon( )将图标放置到外壳盘(Shell Tr a y )里—以后在任务栏里发现的小图
标集。
■ 可以用: : F i n d Window( )搜索桌面上的窗口。
■ 可以用Wi n d o w F r o m P o i n t ( )找到当前窗口在桌面上的点坐标。
■ 可以用: : G e t S y s t e m M e t r i c s ( S M C X S C R E E N )和::GetSystemMetrics (SM_CYSCREEN)获
得屏幕尺寸。
1.10 小结
在本章中我们讨论了如下内容:
■ 使用M F C类和M i c r o s o f t的特征—窗口类(不是C + +类)创建用户界面窗口的M F C应用
程序方法。
16 第一部分基础知识
下载
④告诉任何一个
子窗口的子窗
口,以此类推
子窗口对
象列表
子窗口对
象列表
框架窗
口对象
系统盘窗
口对象
程序管
理器窗
口对象
桌面窗
口对象
窗口管理器
列表
② 然后,窗口管理器
遍览该列表,通知
每个窗口进程重新
绘制自己
③窗口管理器也告知一个
窗口的每个子窗口重新
绘制自己
① 如果屏幕需要刷新,
则窗口管理器从桌面
窗口获得所有最顶层
窗口的列表。该列表
是桌面窗口的子窗口
列表—也称为窗口
管理器列表
■ 用M F C创建和销毁窗口和窗口类的步骤。
■ 系统提供的窗口类。
■ 三种类型的窗口—重叠窗口、弹出窗口和子窗口,并介绍了在应用程序中创建关于
它们的各种各样的窗口。
■ 桌面窗口及其相关的几种主要功能。
在下一章中,我们将讨论M F C提供的类。
本源码包内暂不包含可直接显示的源代码文件,请下载源码包。