代码之家  ›  专栏  ›  技术社区  ›  Scott Saad

tbitbtn和tbutton继承链发生了什么?

  •  3
  • Scott Saad  · 技术社区  · 15 年前

    我最近开始将我的RADStudio2007项目升级到RADStudio2009。我注意到的一件事是,当看似简单的代码突然无法编译时。

    示例代码:

    class CButtonPopupMenu
    {
        // Snip
    
    public:
        void Init( TButton* SrcButton )
        {
            SrcButton->OnClick = OnButtonClick;
        }
    
    private:
        void __fastcall OnButtonClick( TObject* Sender )
        {
            // Do some button click stuff
        }
    };
    
    // Snip
    
    TButton button = new TButton( this );
    TBitBtn bitBtn = new TBitBtn( this );
    CButtonPopupMenu popupButton = new CButtonPopupMenu( button );
    CButtonPopupMenu popupBitBtn = new CButtonPopupMenu( bitBtn );
    

    这都是用来编译的,但是随着2009年的到来,它已经失败了。看看2007年的继承链 TBitBtn 用于派生自 TButton . 因此,任何按钮控件(即onclick)上预期的事件都由 按钮控件 班级。因此,我可以 TBITBTN 类作为 按钮控件 .

    2007继承链:

    • tbitbtn:tbutton(按钮)

    2009继承链:

    • tbitbtn:t自定义按钮
    • t按钮:t按钮

    2009,两者兼而有之 按钮控件 按键按钮 来源于 定制按钮 如果像按钮一样的属性保留在那里,那就没问题了。如果是这样的话,我可以修改代码来处理 定制按钮 相反。不幸的是, 定制按钮 不能容纳这样的东西 点击 . 因此,我不能再治疗 TBITBTN 像一个 按钮控件 . 这两个类现在都有各自独立的类似按钮的属性(即它们都声明了自己的onclick事件)。我的意思是,至少提供一个接口或类似的东西 伊布顿 这两个 按钮控件 TBITBTN 实施。

    似乎这些看似无辜的变化会造成不必要的破坏。这看起来很奇怪,我想知道是否有人知道为什么codegear(或任何相关的框架作者)会做这种事情?

    更重要的是,考虑到这种支离破碎的遗产,是否存在 优雅的 治疗A的溶液 TBITBTN 像一个 按钮控件 ?

    2 回复  |  直到 10 年前
        1
  •  6
  •   Remy Lebeau    15 年前

    tbutton和tbitbtn仍然继续共享一个常见的onclick事件,因为它是从tcontrol级别一路向下实现的,并且一直都是这样。tbutton只是将受保护的tcontrol::onclick事件提升为published,然后tbitbtn将继承该事件。

    在d2009中,tcustombutton和其他tcustom一样…类,不会将受保护成员从基类提升为已发布。tbutton和tbitbtn将受保护的tcontrol::onclick事件提升为单独发布。但事件本身仍然存在于tcontrol级别。

    因为它在tcontrol级别受到保护,所以可以使用访问器类来访问它,即:

    class TCustomButtonAccess
    {
    public:
        __property OnClick;
    };
    
    class CButtonPopupMenu
    {
        // Snip
    
    public:
        void Init( TCustomButton* SrcButton )
        {
            ((TCustomButtonAccess*)SrcButton)->OnClick = OnButtonClick;
        }
    
    private:
        void __fastcall OnButtonClick( TObject* Sender )
        {
            // Do some button click stuff
        }
    };
    

    或者,对于任何通用的tcontrol指针:

    class TControlAccess
    {
    public:
        __property OnClick;
    };
    
    class CControlPopupMenu
    {
        // Snip
    
    public:
        void Init( TControl* SrcControl )
        {
            ((TControlAccess*)SrcControl)->OnClick = OnControlClick;
        }
    
    private:
        void __fastcall OnControlClick( TObject* Sender )
        {
            // Do some click stuff
        }
    };
    

    一个更优雅的解决方案是使用rtti,它还允许您处理其他类型的对象,如tspeedbutton,它们有自己的onclick事件,即:

    #include <TypInfo.hpp>
    
    class TControlAccess
    {
    public:
        __property OnClick;
    };
    
    class CControlPopupMenu
    {
        // Snip
    
    public:
        void Init( TControl* SrcControl )
        {
            TMethod m;
            m.Code = &OnControlClick;
            m.Data = this;
            SetMethodProp(SrcControl, "OnClick", m);
        }
    
    private:
        void __fastcall OnControlClick( TObject* Sender )
        {
            // Do some click stuff
        }
    };
    

    甚至:

    #include <TypInfo.hpp>
    
    class CObjectPopupMenu
    {
        // Snip
    
    public:
        void Init( TObject* SrcObject )
        {
            TMethod m;
            m.Code = &OnObjectClick;
            m.Data = this;
            SetMethodProp(SrcObject, "OnClick", m);
        }
    
    private:
        void __fastcall OnObjectClick( TObject* Sender )
        {
            // Do some click stuff
        }
    };
    
        2
  •  1
  •   devio    15 年前

    如果这是Delphi,我建议在tcustombutton类中使用 作为 运营商:

    if (SrcButton is TButton) then
      (SrcButton as TButton).OnClick := OnButtonClick
    else if (SrcButton is TBitButton)
      (SrcButton as TBitButton).OnClick := OnButtonClick;
    

    C++只是很久以前的事了

    顺便说一句,VCL有时不是包括在按钮、菜单等和调用代码之间提供单一接口的操作吗?