如何子类化 TButton 以便所有者绘制它?

问题描述 投票:0回答:1

我想在 C++Builder 中为

TButton
控件着色。我正在尝试遵循我发现的建议使用
SetWindowLong()
为我的
BS_OWNERDRAW
控件启用
TButton
样式的信息,然后捕获
WM_DRAWITEM
消息。

虽然我确实看到了该按钮的消息,但从未出现过

WM_DRAWITEM
消息。

我正在使用以下代码:

__fastcall TMainForm::TMainForm(TComponent* Owner)
  : TForm(Owner)
{
  OldButtonWndProc  = bTest->WindowProc;
  bTest->WindowProc = NewButtonWndProc;

  SetWindowLong(bTest->Handle,
                GWL_STYLE,
                GetWindowLong(bTest->Handle,
                              GWL_STYLE) | BS_OWNERDRAW);
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::NewButtonWndProc(TMessage &AMsg)
{
  if (AMsg.Msg == WM_DRAWITEM)
  {
    Beep();
  }
  else
  {
    OldButtonWndProc(AMsg); // default handling.
  }
}
//---------------------------------------------------------------------------

我只能假设

BS_OWNERDRAW
标志没有发挥其魔力。我在前后捕获了
GWL_STYLE
以确保设置了
BS_OWNERDRAW
标志。据我所知,确实如此。我还检查了没有设置其他
BS
标志,但它们没有设置。

也许

GWL_STYLE
不是设置这个标志的地方?

winapi c++builder vcl subclassing tbutton
1个回答
0
投票

您应该使用

(Get|Set)WindowLongPtr()
,否则您的代码可能无法在 64 位版本中正常工作。

无论如何,

BS_OWNERDRAW
标志都工作正常。
WM_DRAWITEM
消息只是被发送到按钮的 父窗口,这就是为什么您在子类中看不到它。 您需要改为处理
CN_DRAWITEM
消息,父窗口会将其反射回按钮。

另外,请注意,如果按钮(或父表单)在运行时动态地重新创建其

HWND
(这可能发生),您将丢失
BS_OWNERDRAW
样式,除非您在按钮的新
HWND
上重置它。 处理这种情况的更好方法是从
TButton
派生一个新类,并让它覆盖虚拟
CreateParams()
WndProc()
方法,例如:

class TMyButton : public TButton
{
protected:
    void __fastcall CreateParams(TCreateParams &Params);
    void __fastcall WndProc(TMessage &Message);
};

void __fastcall TMyButton::CreateParams(TCreateParams &Params)
{
    TButton::CreateParams(Params);
    Params.Style |= BS_OWNERDRAW;
}

void __fastcall TMyButton::WndProc(TMessage &Message)
{
  if (Message.Msg == CN_DRAWITEM)
  {
    Beep();
  }
  else
  {
    TButton::WndProc(Message);
  }
}

或者,您可以只使用

TBitBtn
来代替,它已经应用了
BS_OWNERDRAW
样式。

© www.soinside.com 2019 - 2024. All rights reserved.