`
isiqi
  • 浏览: 16480270 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

Delphi对于控件的SuperClassing

阅读更多

Windows内部预定义了一些通用的控件,我们在用这些控件的时候不必再调用RegisterClass注册一个窗口类,只要直接调用CreateWindows,并指定一个预定义的窗口类就可以,比如,我们要创建一个Button,只要用如下形式即可:

CreateWindows(.., ‘BUTTON’,...)

但用Delphi写出来的程序,用SPY看它的某个控件的窗口类名,却是这个控件类的ClassName,比如,一个按钮控件,它的窗口类名是TButtonTButton控件也是封装系统预定义的BUTTON控件,按理它的窗口类名应该是BUTTON才对啊,怎么会变成TButton呢。这个问题长期困扰着我。

昨晚看了一下《Window 95程序设计指南》,其中讲到了Superclassing的技术,可以以系统标准控件为基础,设计新的控件。这个技术使我恍然大悟,赶紧看了一下VCL的代码,果然是用了这样的技术,大喜,以此文记之。

我以一个TButton控件的创建过程,说明Superclassing技术在Delphi控件创建的应用。

TButton创建窗口是在CreateWnd方法开始,下面是创建的一个大概流程:

TButton.CreateWnd;

| TWinControl.CreateWnd;

| | TButton.CreateParams(var Params: TCreateParams);

| | | TButtonControl.CreateParams(var Params: TCreateParams);

| | | | TWinControl.CreateParams(var Params: TCreateParams);

| | | TWinControl.CreateSubClass(var Params: TCreateParams;

| | | ControlClassName: PChar);

| | Windows.RegisterClass(WindowClass)

| | TWinControl.CreateWindowHandle(const Params: TCreateParams);

TWinControl.CreateParams(var Params: TCreateParams)中设定了窗口的一些基本的风格,其中有一句重要,是:

with Params do

begin

...

StrPCopy(WinClassName, ClassName);

...

end;

里面的WinClassName即是窗口类名,这时被赋为控件的类名,即是TButton

TButton覆盖CreateParams,作一些自己的风格设置,其中调用到TWinControlCreateSubClass,是这样调用的:

CreateSubClass(Params, 'BUTTON');

BUTTON就是系统的预定义按钮控件的窗口类名。那么这个方法有什么作用呢,它在里面调用了数个GetClassInfo函数,以获得该窗口类的类风格,类风格填充到Params参数的WindowClass结构成员中。这时WindowClass这个结构就有了BUTTON标准窗口的类风格的数据了。

设置完窗口类的风格后,回到TWinControlCreateWnd方法,打开这个方法的代码来看,有一句非常重要:

FDefWndProc := WindowClass.lpfnWndProc;

因为我们前面已经调用了CreateSubClass获得了BUTTON的窗口类的类风格,并填充在Params参数的WindowClass结构中。所以上面我们看到的这一句是将BUTTON的窗口过程保存到FDefWndProc这个函数指针里面,它是TWinControl的一个成员,请记住这个成员。

接下来调用:

ClassRegistered := GetClassInfo(WindowClass.hInstance, WinClassName, TempClass);

还记得WinClassName吗,是它是Params的成员,在上面它已经被为’TButton’了。检查有这个名字的窗口类是否已经被注册了,如果没有则有下面三句非常重要的代码:

WindowClass.lpfnWndProc := @InitWndProc;

WindowClass.lpszClassName := WinClassName;

if Windows.RegisterClass(WindowClass) = 0 then RaiseLastOSError;

首先将BUTTON窗口的窗口过程设定为InitWndProc。再将它的窗口类名字设定为WinClassName也即是TButton。最后注册窗口类。

好了窗口类注册完了,就调用以下两句:

CreateWindowHandle(Params);

CreateWindowHandle根据Params里面的参数创建窗口,代码比较简单。

这一个TButton的创建过程就完了,那么它是如何享有系统预定义的BUTTON的那些功能的呢。接着往下看。

当在CreateWindowHandle里面调用CreateWindow函数时,系统直接发送一个WM_CREATE消息给这个新建的窗口。而上面我们已经知道这个窗口的窗口函数就是InitWndProc。在它里面调用了:

SetWindowLong(HWindow, GWL_WNDPROC,

Longint(CreationControl.FObjectInstance));

将窗口过程重新指定,关于这个技术李维的《Inside VCL》已经有说明。返正窗口过程最后就到了TWinControlWndProc这个方法去了,以后所有的消息将由这个方法来处理。

那就看看这个方法吧:

TWinControl.WndProc这个方法没有看到什么信息,不过它会调用父类的WndProc,再看看TControl.WndProc; 里面最终调用了TObjectDispatch(Message),将消息通过DMT发送到对应的消息处理方法中,最后还会调用TObjectDefaultHandlerTContorl覆盖了这个方法,而TWinControl也覆盖了这个方法。不过TControl没有我们要的信息。关键就是TWinControlDefaultHandle。在里面终于找到最最重要的这一句:

Result := CallWindowProc(FDefWndProc, FHandle, Msg, WParam, LParam);

还记得FDefWndProc吗,在上面,它被指向了BUTTON类的原始窗口过程。这里调用了它,亦即Windows在内部会自动对TButton的一些BUTTON特性进行处理。

至此Superclassing完成。而我们也看到BUTTON控件变成了TButton控件。呵呵,如果看一下那本《Window 95程序设计指南》,再看一下VCL源码,相信会理解得更清楚。

分享到:
评论

相关推荐

    子类化 超类化 技术分析

    在编程领域,子类化(Subclassing)和超类化(Superclassing)是面向对象编程中的两个重要概念,它们对于代码复用和模块化设计具有关键作用。本文将详细探讨这两种技术,并以MFC(Microsoft Foundation Classes)库...

    《Windows 95 程式设计指南》(含Pascal例子)

    /237 第五章 Window Subclassing和Window Superclassing /325 第六章 讯息拦截(Hooks) /387 第七章 档案的拖放(Drag-and-Drop)技术 /499 第八章 按键的处理 /541 第九章 版本控制(Version Control) /593

    windows95程序设计

    ### Windows95程序设计知识点...总之,《Windows95程序设计》是一部不可多得的技术宝典,无论是对于希望深入了解Windows程序设计原理的专业人士,还是对于希望提升自己编程技巧的程序员来说,都是非常宝贵的学习资源。

    Windows 95 程序设计指南 简体

    6. 程序设计技术:文档中提到了书中包含的内容,如Custom Controls(自定义控件)、Subclassing(子类化)、Superclassing(父类化)和Processing Keystrokes(处理按键)等。这些是Win32 SDK编程中的高级技术,涉及...

    vc超类化实例代码superclass_注释相当全 关于超类化的一切问题这里都有答案_产生多个超类的实例.rar

    超类化(Superclassing)是面向对象编程中的一种技术,它允许我们通过继承一个现有的类(父类或基类)并对其进行扩展或修改来创建新的类。在Visual C++中,超类化是一个强大的工具,它使得程序员可以利用已有的类库...

Global site tag (gtag.js) - Google Analytics