Domanda

Recentemente ho cominciato a aggiornare il mio progetto RAD Studio 2007 per RAD Studio 2009. Una cosa che ho notato è quando apparentemente semplice codice tutto ad un tratto non è riuscito per la compilazione.

Esempio di codice:

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

Questo uso tutto per compilare, ma con il 2009 è mancato. Guardando la catena di ereditarietà per il 2007 TBitBtn usato per derivare da TButton. Pertanto, gli eventi che si prevede alcun controllo sul pulsante (cioè OnClick) sono state condivise dalla classe TButton. Pertanto, sono stato in grado di trattare la mia classe TBitBtn come TButton.

2007 catena di ereditarietà:

  • TBitBtn: TButton

2009 catena di ereditarietà:

  • TBitBtn: TCustomButton
  • TButton: TCustomButton

Nel 2009, sia TButton e TBitButton derivano da TCustomButton , che sarebbe bene Suppongo che se il pulsante mi piace attributi si sono svolte lì. Se questo fosse il caso, ho potuto solo modificare il codice a che fare con un TCustomButton , invece. Purtroppo, TCustomButton non tenere le cose come Su clic . Pertanto, non riesco più a trattare un TBitBtn come un TButton . Entrambe queste classi, ora hanno un proprio pulsante separato come attributi (vale a dire che entrambi hanno un proprio evento OnClick dichiarato). Voglio dire, almeno fornire un'interfaccia o qualcosa, come IButton che sia TButton e TBitBtn implementare.

Sembra che questi tipi di modifiche apparentemente innocenti sono quelli che possono devastare inutili. Questo sembra strano e mi chiedo se qualcuno sa perché CodeGear (o qualsiasi autore quadro è per questo) avrebbero fatto questo tipo di cose?

Ancora più importante, data questa eredità frammentato, è lì e elegante soluzione per trattare una TBitBtn come un TButton

È stato utile?

Soluzione

TButton e TBitBtn si continuano a condividere un evento comune OnClick, così come attuato fino in fondo a livello TControl per cominciare, ed è sempre stato. TButton stava semplicemente promuovendo l'evento TControl :: OnClick protetta ai pubblicato, che TBitBtn avrebbe poi ereditato.

Nel D2009, TCustomButton, come altri TCustom ... classi, non promuove membri protetti da classi base alla pubblicato. TButton e TBitBtn promuovere l'evento protetto TControl :: OnClick al pubblicato singolarmente. Ma l'evento stesso esiste ancora a livello di TControl.

Dal momento che è protetto a livello di TControl, è possibile utilizzare una classe di accesso per raggiungere, vale a dire:

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

In alternativa, per qualsiasi puntatore generale 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
    }
};

Una soluzione più elegante sarebbe quella di utilizzare RTTI invece, che consentirebbe anche di gestire altri tipi di oggetti, come ad esempio TSpeedButton, che hanno un proprio evento OnClick, vale a dire:

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

O ancora:

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

Altri suggerimenti

Se questo è stato Delphi, vorrei suggerire la classe TCustomButton con il e come gli operatori:

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

C ++ è semplicemente troppo tempo fa

A proposito, non ha il VCL comprendono a volte azioni per fornire un'unica interfaccia tra pulsanti, menu, ecc ed invocata codice?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top