我最近开始升级我的RAD室2007年的项目,以RAD室2009年。有一件事我注意到的是当看似简单的代码突然未能编译。

例编码:

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.因此,活动是预期在任何按钮的控制(即击)是共用的 TButton 类。因此,我能够享我的 TBitBtn 类作为一个 TButton.

2007年继承链:

  • TBitBtn:TButton

2009年继承链:

  • TBitBtn:TCustomButton
  • TButton:TCustomButton

2009年,这两个 TButtonTBitButton 来自 TCustomButton, 这将是美好的,我想如果按钮就像属性被关押在那里。如果是这种情况,我可能只是变革的代码处理 TCustomButton 代替。不幸的是, TCustomButton 不抱东西喜欢 .因此,我再也无法治疗 TBitBtn 像一个 TButton.这两个课程,现在有自己的独立的按钮就像属性(即他们两个都有自己的击事件的声明).我的意思是,至少提供一个接口,或者东西,像 IButton 这两个 TButtonTBitBtn 实施。

看来,这些类型的看似无辜的变化是那些可以造成不必要的破坏。这似乎很奇怪,我不知道如果有人知道为什么codegear出现(或者任何框架,提交人对于这个问题)会做这种类型的事情吗?

更重要的是,鉴于这种零散的继承,是那里 优雅 解决方案来治疗 TBitBtn 像一个 TButton?

有帮助吗?

解决方案

TButton和TBitBtn做的仍然继续享有共同击事件,因为它是实现所有的方式在TControl级开始,一直都是。TButton是仅仅促进保护TControl::击事件发表,其TBitBtn会然后继承。

在D2009,TCustomButton,像其他TCustom...类,并不能促进保护成员基类出版。TButton和TBitBtn促进保护TControl::击事件发布的独立。但事件本身仍然存在的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,它们有自己的击事件,即:

#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
    }
};

其他提示

如果这是德尔菲,我会建议的TCustomButton类的 作为 经营者:

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

C++只是很久以前

顺便说一句,不VCL的某个时候包括行动提供一个单一的接口之间的按钮,菜单等并调用的密码?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top