如何自定义VCL组件的Caption 属性

How to customize the Caption property of a VCL component

(C++Builder 11)

因为我需要使用 TSpeedButton 和字形上的标题(不是在字形的顶部、底部、左侧或右侧),所以我遵循了 Ted Lyngmo 的建议(Caption position in a TSpeedButton) 创建一个新的 VCL 组件。 我创建了一个从 TCustomSpeedButton 开始的新组件,我只发布了几个 属性,不包括 Caption。我已经添加了我的 CustomCaption 属性 并且我试图覆盖 Paint() 方法以在按钮中间写入文本。 生成的组件可以加载一个字形来显示按下和未按下状态,CustomCaption 的内容写在它的中间。

但我的 CustomCaption 与原来的 Caption 相去甚远。

首先,如果我更改 CustomCaption 的内容,在设计时,按钮不会发生变化,直到我不点击它(并且我执行 Paint()设计器中的方法,我认为...)

然后,如果我更改字体,在设计时,我的 CustomCaption 字体根本不会改变。

我尝试使用 CM_FONTCHANGEDCM_TEXTCHANGED 消息,但可能使用的方式不正确。

这是代码

//header file
class PACKAGE TSpecialSpeedButton : public TCustomSpeedButton
{
    private:
        String fCustomCaption;
        //int fCustomCaptionTop, fCustomCaptionLeft;

        MESSAGE void __fastcall CMFontChanged(TMessage &Msg);
        MESSAGE void __fastcall CMTextChanged(TMessage &Msg);

    protected:
        void __fastcall Paint() override;


    public:
        __fastcall TSpecialSpeedButton(TComponent* Owner) override;

    __published:
        __property String CustomCaption = {read = fCustomCaption, write = fCustomCaption};
        //__property int CustomCaptionTop = {read = fCustomCaptionTop, write = fCustomCaptionTop};
        //__property int CustomCaptionLeft = {read = fCustomCaptionLeft, write = fCustomCaptionLeft};
        __property Glyph;
        __property GroupIndex = {default=0};
        __property Font;
        __property NumGlyphs = {default=1};
        __property OnClick;

    BEGIN_MESSAGE_MAP
            VCL_MESSAGE_HANDLER(CM_FONTCHANGED, TMessage, CMFontChanged)
            VCL_MESSAGE_HANDLER(CM_TEXTCHANGED, TMessage, CMTextChanged)
    END_MESSAGE_MAP(TCustomSpeedButton)

};

//cpp file
static inline void ValidCtrCheck(TSpecialSpeedButton *)
{
    new TSpecialSpeedButton(NULL);
}
//---------------------------------------------------------------------------
__fastcall TSpecialSpeedButton::TSpecialSpeedButton(TComponent* Owner)
    : TCustomSpeedButton(Owner)
{
    //fCustomCaptionTop = 0;
    //fCustomCaptionLeft = 0;

    Height = 50;
    Width = 50;
}
//---------------------------------------------------------------------------
namespace Tspecialspeedbutton
{
    void __fastcall PACKAGE Register()
    {
        TComponentClass classes[1] = {__classid(TSpecialSpeedButton)};
        RegisterComponents(L"My Components", classes, 0);
    }
}
//---------------------------------------------------------------------------

void __fastcall TSpecialSpeedButton::Paint()
{
    TRect PtRect;

    TCustomSpeedButton::Paint();

    PtRect.Left = 0;
    PtRect.Top = 0;
    PtRect.Right = Width;
    PtRect.Bottom = Height;

    Canvas->Font = Font;    //this seems to have no effect

    DrawTextW(Canvas->Handle, fCustomCaption.c_str(), fCustomCaption.Length(), &PtRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

}
//---------------------------------------------------------------------------

void __fastcall TSpecialSpeedButton::CMFontChanged(TMessage &Msg)
{
    Invalidate();
}
//---------------------------------------------------------------------------

void __fastcall TSpecialSpeedButton::CMTextChanged(TMessage &Msg)
{
    Invalidate();
}
//---------------------------------------------------------------------------

我无法以正确的方式管理 CustomCaption,就像原来的 Caption 一样。 我已经通过 Internet 在 Embarcadero docwiki - Component Writer's Guide 和文件 Vcl.Buttons.pas 中搜索了信息,但我没有找到正确的方法,有人可以帮助我吗?

Embarcadero 不久前进行了一些更改,导致 Windows 资源(例如 TFont、TBrush、TPen 等)出现细微问题。您 运行 遇到的问题是 TFont.Assign 并不总是导致 TCanvas 重新创建 Windows 字体对象。要强制重新创建字体对象,您需要强制对 TFont.Changed 进行内部调用。执行此操作的一种 hacky 方法是将不需要的值分配给 TFont.Color,然后将其设置回您真正想要的颜色。例如:

Canvas->Font = Font;
Canvas->Font->Color = clNone;
Canvas->Font->Color = Font->Color;

I'm not able to manage the CustomCaption in the right way

我不确定你所说的“以正确的方式”是什么意思。如果您的意思是您想要更改 CustomCaption 以导致重绘,请为 属性 添加一个编写器,然后在值更改时调用 Invalidate。

protected:
  void __fastcall SetCustomCaption(String Value);

__published:
  __property String CustomCaption = { read = fCustomCaption, write = SetCustomCaption };

void __fastcall TSpecialSpeedButton::SetCustomCaption(String Value)
{
  if (fCustomCaption != Value)
  {
    fCustomCaption = Value;
    Invalidate();
  }
}

CM_TEXTCHANGED是继承的Text/Caption属性发生变化时发送的Windows消息。由于您没有使用继承的 属性 那么您很可能不需要处理该消息。除非您想始终将其设置回空字符串。