WIN32汇编语言教程:第09章 通用控件 · 9.6 控件的超类化(1)

9.6.1 什么是控件的超类化

子类化是对窗口功能的调整和扩展,那么超类化是什么呢?超类化是对类的调整和扩展,在C++中,可以通过继承和扩展某个基类来形成一个派生的类,超类化可以完成的功能就和这相似。

超类化主要用在什么地方呢?举例来说,如果需要一个只能输入16进制字符的编辑框,那么可以通过对编辑框窗口子类化来实现,9.5节的例子就是如此,但是当应用程序需要大量使用这种16进制编辑框时,该如何处理呢?方法有3种:

● 创建自己的类,自己书写所有的功能代码。

● 创建多个Edit控件,并把它们全部子类化。

● 超类化Edit控件,用Edit控件当做基类派生出一个新的类,并用这个类来建立多个“新Edit”控件窗口。

第一种方法在9.5节中就被“枪毙”了,几乎没有人去干这种吃力不讨好的事情;第二种方法要好一点,但子类化一大堆的控件也是一件令人头痛的事情;这时就应该使用超类化Edit类方法,当从Edit类派生出一个新的“16进制编辑类”后,接下来直接使用这个类就能够创建出一大堆的16进制编辑框。

9.6.2 控件超类化的实现

各种自定义的窗口和不同的控件窗口之所以看上去千姿百态,功能也各不相同是因为两个原因:首先用来表示类属性的WNDCLASSEX结构定义不同,造成窗口的风格与形状等各不相同;其次,不同窗口类使用的窗口过程不同,这些不同的窗口过程对各种消息的处理方法各不相同,造成窗口的功能不同。

设想这样一种情况:如果自定义一个类,这个类的WNDCLASSEX结构中定义的风格、形状、光标与图标等所有属性都和Edit类相同,然后在自己的类中将窗口过程地址指向Edit类的窗口过程(或者原样拷贝Edit类的窗口过程代码),这个类会实现什么样的功能呢?答案是:除了类的名称不同之外,用这个类创建的窗口的形状和所有功能将和Edit框一模一样!这时候,就相当于从Edit类派生出了一个相同的类来。

这样一来就不难设想从基类派生出新类的方法,我们可以获取基类的WNDCLASSEX结构,然后保持结构中的大部分字段不变,仅修改个别需要自定义的属性,那么新类的窗口风格就和基类类似,如果还需要扩充某些功能的话,可以将结构中的窗口过程地址指到自己的子程序中,这样就可以扩展基类的功能。最后,使用这个修改后的结构以自定义的名称注册一个类,一个新的类就派生出来了。

对基类进行超类化的时候,如果修改的仅是窗口风格,那么使用派生类建立的窗口和基类窗口会实现同样的功能,但外观上会有所不同;如果仿照子类化窗口的方法修改窗口过程,那么使用派生类建立的窗口和基类窗口的外形是相同的,但是功能上会有所不同。

使用GetClassInfoEx函数可以获取现存的类的属性,对基类进行超类化的第一步就是使用这个函数获取基类的WNDCLASSEX 结构。GetClassInfoEx函数的使用方法是:

   invoke GetClassInfoEx,hinst,lpszClass,lpwcx

hinst参数是创建这个类的应用程序的实例句柄,如果要获取某个Windows预定义类的属性,那么这个参数使用NULL。

lpszClass参数指向一个字符串,用来定义类的名称。lpwcx参数指向一个WNDCLASSEX结构,用来返回指定类的属性。在调用函数之前,结构中的cbSize必须正确地设置为WNDCLASSEX结构的长度,否则函数的执行可能失败。

获取WNDCLASSEX结构以后,可以根据需要修改结构的内容。如果需要派生出一个功能不同的新类,可以将窗口过程地址设置到自己的程序中,当然原来的地址应该被保存下来,以便收到不感兴趣的消息时转发到原来的窗口过程中。除了修改需要自定义的属性外,还有两个字段是必须修改的:hInstance字段必须设置为应用程序的实例句柄;lpszClassName必须指向新的派生类的类名。完成了这些修改后,使用经过修改的WNDCLASSEX注册一个新的类就大功告成了。

让我们通过一个简单的例子来演示超类化的过程,例子中建立了一个对话框,并在对话框中定义了多个从Edit类派生出来的16进制编辑类,这些类实现的功能和9.5节中的例子是一样的,全部的源代码在所附光盘的Chapter09\SuperClass目录中,SuperClass.rc文件的定义如下:

//##################################################################
#include             <resource.h>
//##################################################################
#define ICO_MAIN      1000
#define DLG_MAIN      1000
//##################################################################
ICO_MAIN          ICON       "Main.ico"
//##################################################################
DLG_MAIN DIALOG 107, 102, 126, 82
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "SuperClass"
FONT 9, "宋体"
{
 CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,5,115,12
 CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,20,115,12
 CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,35,115,12
 CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,50,115,12
 CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,65,115,12
}
//##################################################################

读者可以看到,对话框中定义了多个HexEdit类,但是系统中并没有预定义这种名称的类,这就是将要从Edit类中派生的类。SuperClass.asm文件的内容如下:

上页:第09章 通用控件 · 9.5 窗口的子类化(3) 下页:第09章 通用控件 · 9.6 控件的超类化(2)

第09章 通用控件

版权所有 © 中山市飞娥软件工作室 证书:粤ICP备09170368号