TForm:添加消息处理程序并调用继承

TForm: Add a message handler and call inherited

假设我需要在我的 C++ Builder cpp 文件中创建一个 Windows 消息处理程序。

我会像这样为 WM_SIZE 编写处理程序:

h 文件:

BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(WM_SIZE, TWMSize, OnWMSize)
END_MESSAGE_MAP(TControl)

void __fastcall OnWMSize(TWMSize &msg);

cpp 文件:

void __fastcall TForm1::OnWMSize(TWMSize &msg)
{
    if (msg.SizeType == SIZE_MAXIMIZED)
        Caption = "Maximized";

    // This is a Delphi call and won't work in C++:
    // inherited;

    // Cpp call. Won't compile due to method visibility (private)
    // TForm::WMSize(msg);

    // Cpp call. Compiles but doesn't get expected behavior
    DefaultHandler((void*)&msg);
}

如示例所示,使用 Delphi 这非常简单,只需调用 inherited.

但是使用 C++,我如何在 C++ Builder 中调用基 class? WMSize 方法在 TScrollingWinControl 中声明为私有方法。

在此示例中,不调用基 class 会破坏 Anchors 功能。使用 DefaultHandler 也不能解决问题。

我是不是遗漏了什么明显的东西?

首先,您将错误的 class 类型传递给了 END_MESSAGE_MAP()。您需要指定 直系父级 class,在本例中为 TForm,而不是 TControl:

BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(WM_SIZE, TWMSize, OnWMSize)
END_MESSAGE_MAP(TForm) // <-- here

现在,话虽如此,MESSAGE_MAP 只是一种覆盖虚拟 Dispatch() 方法的奇特方式:

#define BEGIN_MESSAGE_MAP   virtual void __fastcall Dispatch(void *Message) \
        {                                           \
          switch  (((PMessage)Message)->Msg)        \
          {

#define VCL_MESSAGE_HANDLER(msg,type,meth)          \
          case    msg:                              \
            meth(*((type *)Message));               \
            break;

// NOTE: ATL defines a MESSAGE_HANDLER macro which conflicts with VCL's macro. The
//       VCL macro has been renamed to VCL_MESSAGE_HANDLER. If you are not using ATL,
//       MESSAGE_HANDLER is defined as in previous versions of BCB.
//
#if !defined(USING_ATL) && !defined(USING_ATLVCL) && !defined(INC_ATL_HEADERS)
#define MESSAGE_HANDLER  VCL_MESSAGE_HANDLER
#endif // ATL_COMPAT

#define END_MESSAGE_MAP(base)           default:    \
                        base::Dispatch(Message);    \
                        break;                      \
          }                                         \
        }

因此,您的 MESSAGE_MAP 解析为以下代码逻辑:

virtual void __fastcall Dispatch(void *Message)
{
  switch  (((PMessage)Message)->Msg)
  {
    case WM_SIZE:
      OnWMSize(*((TWMSize *)Message));
      break;
    default:
      TForm::Dispatch(Message);
      break;
  }
}

如您所见,END_MESSAGE_MAP() 只是将未处理的消息传递给基本 class TForm::Dispatch() 方法。您必须在消息处理程序中执行相同的操作,例如:

void __fastcall TForm1::OnWMSize(TWMSize &msg)
{
    if (msg.SizeType == SIZE_MAXIMIZED)
        Caption = "Maximized";

    TForm::Dispatch(&msg);
}