Question

J'ai récemment commencé à mettre à jour mon projet RAD Studio 2007 à RAD Studio 2009. Une chose que je remarque est quand un code simple en apparence tout d'un coup a échoué à compiler.

Exemple de code:

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

Cette toute utilisation à compiler, mais avec 2009, il est défaillant. En regardant la chaîne d'héritage pour 2007 TBitBtn utilisé pour tirer de TButton. Par conséquent, les événements qui sont attendus sur un bouton de commande (à savoir OnClick) ont été partagés par la classe TButton. Par conséquent, je suis en mesure de traiter ma classe TBitBtn comme TButton.

chaîne d'héritage 2007:

  • TBitBtn: TButton

chaîne d'héritage 2009:

  • TBitBtn: TCustomButton
  • TButton: TCustomButton

En 2009, à la fois TButton et TBitButton dérivent de TCustomButton , ce qui serait bien, je suppose que si le bouton comme les attributs y ont eu lieu. Si tel était le cas, je pouvais changer le code pour faire face à une TCustomButton à la place. Malheureusement, TCustomButton ne tient pas des choses comme OnClick . Par conséquent, je ne peux plus traiter un TBitBtn comme TButton . Ces deux classes ont maintenant leur propre bouton séparé comme attributs (à savoir qu'ils ont tous deux leur propre événement OnClick déclaré). Je veux dire, au moins fournir une interface ou quelque chose, comme IButton que les deux TButton et TBitBtn mettre en œuvre.

Il semble que ces types de changements apparemment innocents sont ceux qui peuvent causer des ravages inutiles. Cela semble bizarre et je me demande si quelqu'un sait pourquoi CodeGear (ou tout auteur-cadre pour cette question) feraient ce genre de chose?

Plus important encore, compte tenu de cet héritage fragmenté, est là et élégant solution pour traiter une TBitBtn comme TButton ?

Était-ce utile?

La solution

TButton et TBitBtn ne continuent à partager un événement OnClick commun, car il est mis en œuvre tout en bas au niveau TControl pour commencer, et a toujours été. TButton ne faisait que la promotion de l'événement TControl :: OnClick protégé à publier, qui TBitBtn alors hériter.

Dans D2009, TCustomButton, comme les autres ... TCustom cours, ne favorise pas les membres protégés des classes de base pour publication. TButton et TBitBtn promouvoir l'événement TControl :: OnClick protégé à publier individuellement. Mais l'événement lui-même existe encore au niveau de TControl.

Comme il est protégé au niveau TControl, vous pouvez utiliser une classe accesseur pour l'atteindre, à savoir:

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

Ou, pour tout pointeur de TControl générale:

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

Une solution plus élégante serait d'utiliser à la place RTTI, qui vous permettra également de gérer d'autres types d'objets, tels que TSpeedButton, qui ont leur propre événement OnClick, à savoir:

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

Ou même:

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

Autres conseils

Si tel était Delphi, je suggère la classe TCustomButton avec est et comme opérateurs:

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

C ++ est tout simplement trop il y a longtemps

BTW, ne pas la VCL inclut parfois Actions pour fournir une interface unique entre les boutons, menus, etc et le code invoqué?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top