【问题标题】:Subclassing descendant of VCL TWinControlVCL TWinControl 的子类化后代
【发布时间】:2013-04-02 17:28:59
【问题描述】:

使用伪函数进行子类化:

CreateSpecialHandle(TWinControl *Control, const TCreateParams &Params, const AnsiString SubClass)  
{  
......;  
    set Control DefWndProc to SubClass.lpfnWndProc  
    set Control WindowHandle from CreateWindowEx 
......;  
subclass(TWinControl *Control);  
}

subclass(TWinControl *Control)
{
  ......;
  oldWProc = (void*)GetWindowLong(Control->Handle, GWL_WNDPROC);
  oldDefWProc = (void*)(Control->DefWndProc);
  oldWindowProc = Control->WindowProc;
  MakeObjectInstance(newWProc) for SetWindowLong
  MakeObjectInstance(newDefWProc) for Control->DefWndProc
  Control->WindowProc = newWindowProc;
  ......;
}

现在,我们遇到了子类控件的意外行为。 WM_NCHITTEST 结果 0 等...
例如当newWProc拦截WM_NCHITTEST并将Result设置为HTCLIENT 我们有鼠标响应,但是,如果没有将msg.result 设置为 1 来响应我的错误和错误的子类化,那么我们还需要手动处理什么?

  • newWProc 回调oldWProc
  • newDefWProc 回调oldDefWProc
  • newWindowProc 致电oldWindowProc

我们是否也必须对子类控件的父控件进行子类化?
此外,发送 WM_GETTEXT 结果时缓冲区为空。
显然,我们在这里做错了什么。我们需要解释,
提前谢谢大家
更新:

   in TDCEdit:public TCustomEdit overriding CreateWindowHandle
   void __fastcal CreateWindowHandle(const TCreateParams &Params)
      {
       CreateSpecialHandle(this,Params,TEXT("EDIT"));
      }
     void CreateSpecialHandle(TWinControl *Control,const TCreateParams &Params, AnsiString SubClass)  
     {
     ... 
     Control->WindowHandle = CreateWindowEx(...,"EDIT",....);
     ....
     subclass(Control);
     }
     subclass(TWinControl* Control)
     {
     ......;
     oldWProc = (void*)GetWindowLong(Control->Handle, GWL_WNDPROC);
     oldDefWProc = (void*)(Control->DefWndProc);
     oldWindowProc = Control->WindowProc;
     MakeObjectInstance(newWProc) for SetWindowLong
     MakeObjectInstance(newDefWProc) for Control->DefWndProc
     Control->WindowProc = newWindowProc;
     ......;
     }

现在,当我使用 TDCEdit 并拦截 Message.Msg == WM_NCHITTEST
在 newWProc Message.Result 内部为 0 并在所有消息处理链中保持为 0。
请注意,子类化 TCustomEdit 是我们需要子类化的其他控件之一
在项目中,我们尝试对所有人使用相同的子类(TWinControl*)函数。

这里是 newWProc 的一部分,还有几行专注于问题

void __fastcall TControlWrapper::newWProc(Messages::TMessage &Message)
 {
   if(Message.Msg == WM_NCHITTEST ) // TEST
            if(Message.Result == 0) 
                  Message.Result=1;//<- WHY I NEED TO DO THIS
    if( Message.Msg == WM_DESTROY) {
      HandleWMDestroy(Message);
      return; 
    }
      CallWindowProcW( (int(__stdcall*)())oldWProc, 
              Handle, Message.Msg, Message.WParam, 
              Message.LParam);

     if(Message.Msg == WM_NCHITTEST )
            if(Message.Result == 0)Message.Result=1;//<- OR THIS


 }

【问题讨论】:

    标签: c++ c++builder vcl


    【解决方案1】:

    这是一个令人困惑的问题 - 您的代码示例不是 C++ 并没有帮助。

    set Control DefWndProc to SubClass.lpfnWndProc
    
    例如,

    不是 C++ 函数中的一行。你能显示你的实际代码吗?

    我可以猜测您要做什么:您是否要对窗口(可能是表单?)进行子类化,以便在单击鼠标时移动它?如果是这样,您不需要像使用GetWindowLong 那样做任何原始Windows API 样式的子类化。在 C++ Builder 中,VCL 是围绕 Windows API 的面向对象的包装器,您可以通过以下两种更简洁的方式之一来实现这一点:

    1. 新建WindowProc并设置;这是一个指向新窗口过程的属性,您也只需调用旧的;
    2. 创建TWinControl 的后代类(如果您正在使用表单,则已经有一个)并实现虚拟方法WndProc

    the Embarcadero documentation on subclassing WndProc 中的#1 示例,在 Delphi 中(但您应该能够轻松地将其转换为 C++)。

    #2 的示例,最干净的 OO 版本,在这里,它实际上也展示了如何做你想做的事情:C++Builder: Create a TForm with BorderStyle bsNone that is nevertheless movable and resizable

    鉴于您似乎想要做的事情,我建议您使用#2。

    【讨论】:

    • 我正在尝试继承 tcustomedit,覆盖 createhandle,然后将 wndproc 更改为 newWProc 等,就像我在 Q 中写的那样,我将使用代码更新 Q
    猜你喜欢
    • 2012-02-22
    • 2012-05-12
    • 1970-01-01
    • 2011-01-06
    • 1970-01-01
    • 2013-05-22
    • 2022-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多