65.9K
CodeProject 正在变化。 阅读更多。
Home

双重子类化(运行时窗体编辑器)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (17投票s)

2003年5月22日

4分钟阅读

viewsIcon

92375

downloadIcon

1451

本文介绍了一种对已子类化的控件进行子类化(双重子类化)的方法。示例包含一个运行时窗体编辑器。

引言

本文解释了如何对已子类化的控件进行子类化。其中包含一个简单的运行时窗体编辑器。

引言

我在公司工作时有一个项目,需要为不同的客户提供不同的窗体,所以团队决定创建一个运行时窗体编辑器,以便为每个客户编辑窗体。为了实现这一点,我需要一种方法来控制窗体视图或对话框上的所有控件;使我能够调整控件大小、移动它们或隐藏它们。我想对对话框/窗体视图上的控件进行子类化,以便控制它们,然而主要问题是大多数控件已经被子类化了。我编写了一个类(CDblSubclassWnd),即使控件已被子类化,它也能对其进行子类化。

解释

其工作原理是,消息首先进入一个名为 PreWndProc 的函数,然后继续进入控件的原始 WndProc,在它完成后,再进入一个名为 PostWndProc 的函数。

该类易于使用。文章中的演示包含一个非常简单的窗体编辑器,允许您在编辑模式下简单地移动窗体上的控件。使用该类非常简单。您需要与 CDblSubclassWnd 类中的三个方法进行交互。所有方法都是静态的。

  • 第一步是向该类提供两个函数指针,CDblSubclassWnd 类将调用它们来传递子类化控件的消息。

    方法签名如下:

    static void SetDblSubclassWndProc(
                    DBLSUBCLASS_WNDPROC *pPREPointer = NULL, 
                    DBLSUBCLASS_WNDPROC *pPOSTPointer = NULL
                );
    
    第一个参数是指向函数的指针(PreWndProc),该函数将在消息传递给控件的主 WndProc(或另一个 Proc,如果它已被子类化)之前被调用。此函数将为您提供在消息到达控件之前修改消息的选项。第二个参数是指向将在控件处理完消息后调用的函数的指针(PostWndProc)。您可以使用此指针来检查控件已更改(或返回)的值。

    DBLSUBCLASS_WNDPROC 函数指针定义如下:

    typedef LRESULT CALLBACK DBLSUBCLASS_WNDPROC(
                                 CWnd*,
                                 HWND,
                                 UINT,
                                 WPARAM,
                                 LPARAM,
                                 bool &
                             );
    

    第一个参数是指向当前消息所属的控件窗口类的指针。第二个参数是窗口的句柄。第三个参数(UINT)是消息编号本身,接下来的两个参数(WPARAM, LPARAM)是传递给每个窗口消息的两个参数,它们的含义取决于实际的消息。最后一个参数(对 bool 的引用)用于指示您是否希望 DblSubclassed 引擎停止路由消息并返回您的两个函数之一(pPREPointer, pPOSTPointer)返回的值。为了更清晰地说明这一点,举个例子,如果您有一个按钮并且点击了它,点击消息 BN_CLICKED 将首先转到您指定的 PRE 函数指针,如果您不希望此消息继续传递到控件的 WndProc,您可以通过将布尔值(传递给 DBLSUBCLASS_WNDPROC 函数的最后一个参数)设置为 false 来阻止此消息,这样消息将被丢弃,不会到达控件。

  • 设置好 PreWndProcPostWndProc 后,就可以实际调用方法来子类化控件了。
    void CDblSubclassWnd::SubclassChildsRecurs(
                  HWND hWnd, 
                  DBLSUBCLASS_RECURSIVECALLBACKPROC *pFunc
              )
    
    您调用此方法,例如,提供您正在工作的对话框的句柄。该函数将遍历对话框上的所有控件,并为每个控件调用函数参数 DBLSUBCLASS_RECURSIVECALLBACKPROC 所指向的函数。引擎将为将要子类化的每个控件调用此函数,其任务是决定是否要子类化该控件。

    例如,如果您想子类化对话框上的所有按钮而不是所有控件,在您的 RecursiveCallBack 函数中,您将测试控件是否为按钮(控件的类),并且只为按钮控件返回 true。RecursiveCallBack 仅接受一个 HWND 参数(用于对控件进行测试),并返回一个布尔值以指示是否要子类化指定的控件。

  • 在子类化控件后,消息将开始流向您在第一步调用 SetDblSubclassWndProc 时指定的 PREPOST WindowProc。当您想结束此效果时,可以使用 UnSubclassChildsRecurs 来取消双重子类化控件。它的使用方法很简单,您提供主窗口(例如示例中的对话框)的句柄,它将遍历属于它的控件,并取消所有之前被子类化的控件的子类化。

希望您觉得这篇文章对您有所帮助。

历史

发布日期:2003 年 5 月 22 日

© . All rights reserved.