Cosa è successo a TBitBtn e TButton catena di ereditarietà?
-
09-09-2019 - |
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
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?