Frage

Ich habe vor kurzem habe begann mein RAD Studio 2007-Projekt zu RAD Studio 2009. Eine Sache, die ich bemerkt, ein Upgrade ist, wenn scheinbar einfachen Code ganz plötzlich zu kompilieren gescheitert.

Beispielcode:

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 );

Das alles Gebrauch zu kompilieren, aber mit 2009 es scheitern. Mit Blick auf die Vererbungskette für 2007 TBitBtn verwendet von TButton abzuleiten. Daher Ereignisse, die auf eine beliebige Taste Steuerung erwartet werden (d OnClick) waren von der TButton Klasse geteilt. Deshalb konnte ich meine TBitBtn Klasse als TButton behandeln.

2007 Vererbungskette:

  • TBitBtn: TButton

2009 Vererbungskette:

  • TBitBtn: TCustomButton
  • TButton: TCustomButton

Im Jahr 2009 beide TButton und TBitButton leiten sich von TCustomButton , was in Ordnung wäre, ich nehme an, wenn Sie die Taste wie Attribute dort gehalten wurden. Wenn dies der Fall wäre, könnte ich nur den Code ändern , um mit einem TCustomButton statt. Leider TCustomButton die Dinge nicht halten wie OnClick . Daher kann ich nicht mehr ein TBitBtn behandeln wie ein TButton . Beide Klassen haben nun ihre eigene separate Taste wie Attribute (das heißt, sie haben beide ihre eigenen OnClick Ereignis deklariert). Ich meine, zumindest eine Schnittstelle oder so etwas, wie IButton , dass sowohl TButton und TBitBtn implementieren.

Es scheint, dass diese Art von scheinbar harmlose Veränderungen sind diejenigen, die unnötigen Schaden anrichten können. Dies scheint seltsam und frag mich, ob jemand weiß, warum CodeGear (oder jeder Rahmen Autor für diese Angelegenheit) würde diese Art der Sache tun?

Noch wichtiger ist, angesichts dieser fragmentierten Erbe, gibt es und elegant Lösung TBitBtn wie ein TButton

zur Behandlung von
War es hilfreich?

Lösung

TButton und TBitBtn haben weiterhin noch ein gemeinsames Ereignis OnClick teilen, da es den ganzen Weg umgesetzt wird unten am TControl Ebene mit zu beginnen, und immer war. TButton nur, was das geschützte TControl :: OnClick Ereignis veröffentlicht Förderung, die TBitBtn würde dann erben.

In D2009, TCustomButton, wie andere TCustom ... Klassen, fördert nicht geschützte Mitglieder von Klassen Basis veröffentlicht. TButton und TBitBtn Förderung der geschützten TControl :: OnClick Ereignis einzeln veröffentlicht. Aber das Ereignis selbst existiert noch in der TControl Ebene.

Da es sich bei der TControl Ebene geschützt ist, können Sie einen Accessor-Klasse verwenden, um es zu erreichen, das heißt:

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

Oder, für jeden allgemeinen TControl Zeiger:

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

Eine elegantere Lösung wäre RTTI sein, anstatt zu verwenden, die auch erlauben würden Ihnen andere Arten von Objekten, wie TSpeedButton zu handhaben, die ihr eigenes OnClick-Ereignis haben, das heißt:

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

Oder auch:

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

Andere Tipps

Wenn diese Delphi ist, würde ich die TCustomButton Klasse mit dem vorschlägt, ist und wie Operatoren:

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

C ++ ist einfach zu lange her

btw, hat die VCL irgendwann nicht Aktionen umfasst eine einzige Schnittstelle zwischen Tasten zur Verfügung zu stellen, Menüs usw. und aufgerufen Code?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top