问题
I wrote a C++ program using Borland C++ Builder 5. The program dynamically creates an array of TCheckBox
objects. I have tried to write an OnClick
event handler that would identify which checkbox is being clicked and execute some instructions based on that. My event handler is based on similar posts to this website, but I cannot seem to make it work.
Here is the (abbreviated) code
// Header declaration
void __fastcall CBoxClick(TObject *Sender);
// End Header
// CBoxClick function (the event handler)
void __fastcall CBoxClick(TObject *Sender){
if (dynamic_cast<TCheckBox*>(Sender)!=NULL){
//Do stuff
}
else{
Form1 -> Debug -> Text = "Object is not a TCheckBox";
}
}
void ChkBoxInit(void){
int i; //Loop counter index
TCheckBox* ChkBx[NCARDS]; //Define array of type checkboxes
for(i = 0; i < NCARDS; i++){ //Initalize each checkbox
ChkBx[i] = new TCheckBox(Form1); //Create a new checkbox
ChkBx[i] -> Parent = Form1; //Define parent of checkbox
ChkBx[i] -> Tag = i; //Set value of Tag to index
// Other CheckBox parameters here such as Height, Width, Top, Left, Name are here
// Next, call event handler. I've tried the following 2 statements with the comment results
ChkBx[i] -> OnClick = CBoxClick(ChkBx[i]); // Results in E2109: Not an allowed type
ChkBx[i] -> OnClick = CBoxClick; /* Alternate try - Results in E2034: Cannot convert
'void (_fastcall *)(TObject *)' to
'void (_fastcall * (_closure )(TObject *))(TObject *)' */
} //End of for loop
} //End of function
回答1:
CBoxClick()
is not a member of your Form class.
Within your cpp file, the compiler sees it as a standalone function. That is what the error message is complaining about when the assignment of the OnClick
event fails (non-static class methods have the __closure
attribute, non-members do not).
Make sure CBoxClick()
is declared inside your Form class in the header file:
class TForm1 : public TForm
{
...
public:
...
void __fastcall CBoxClick(TObject *Sender); // <-- add this
...
};
And then change this line in your cpp file:
void __fastcall CBoxClick(TObject *Sender){
To this instead:
void __fastcall TForm1::CBoxClick(TObject *Sender){
And then change your assignment of the OnClick
event from this:
ChkBx[i]->OnClick = CBoxClick;
To this instead (since ChkBoxInit()
itself appears to not be a member of the Form class, either):
ChkBx[i]->OnClick = Form1->CBoxClick;
The first syntax you tried (OnClick = CBoxClick(ChkBx[i]);
) is just plain wrong, as you are actually calling CBoxClick()
and then trying to assign its void
return value to OnClick
, which obviously will not work. You need to assign the address of CBoxClick()
to OnClick
, and that will work only for non-static class methods, not for standalone functions (well, it CAN be done, but it requires different code involving a type-cast hack utilizing the TMethod
struct).
Also, you should not be using dynamic_cast
. Since you know the Sender
will always be a TCheckBox
, use static_cast
instead:
void __fastcall TForm1::CBoxClick(TObject *Sender){
TCheckBox *cb = static_cast<TCheckBox*>(Sender);
//Do stuff with cb...
}
UPDATE: Now, with that said, a better option is to get rid of ChkBoxInit()
altogether and do the array initialization inside the Form's own constructor instead:
class TForm1 : public TForm
{
...
private:
...
void __fastcall CBoxClick(TObject *Sender); // <-- moved here
...
public:
__fastcall TForm1(TComponent *Owner); // <-- constructor
...
};
__fastcall TForm1::TForm1(TComponent *Owner)
: TForm(Owner)
{
TCheckBox* ChkBx[NCARDS]; //Define array of type checkboxes
for(int i = 0; i < NCARDS; i++){ //Initalize each checkbox
ChkBx[i] = new TCheckBox(this); //Create a new checkbox
ChkBx[i] -> Parent = this; //Define parent of checkbox
ChkBx[i] -> Tag = i; //Set value of Tag to index
// Other CheckBox parameters here such as Height, Width, Top, Left, Name are here
// Next, setup event handler
ChkBx[i]->OnClick = CBoxClick;
} //End of for loop
}
void __fastcall TForm1::CBoxClick(TObject *Sender)
{
TCheckBox *cb = static_cast<TCheckBox*>(Sender);
// Do stuff with cb...
}
回答2:
Remy - I'm still having trouble using the editor. Here is the working code which is based on your first response with one small change. Thank you for your help.
`// .h File----------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Deal;
TButton *Reset;
TButton *Help;
TButton *Quit;
TEdit *Debug;
void __fastcall QuitClick(TObject *Sender);
void __fastcall ResetClick(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
void __fastcall CBoxClick(TObject *Sender); //CheckBox Event Handler prototype
};
// .cpp File ----------------
void ChkBoxInit(void){
int i; //Loop counter index
TCheckBox* ChkBx[NCARDS]; //Define array of type checkbox
for(i = 0; i < NCARDS; i++){ //Initalize each checkbox
ChkBx[i] = new TCheckBox(Form1); //Create a new checkbox
ChkBx[i] -> Parent = Form1; //Define parent of checkbox
// ..... Various parameters of ChkBx[i] go here (height, Width, Top, Left, etc.)
ChkBx[i] -> Tag = i; //Use index value as tag
` ChkBx[i] -> OnClick = Form1 -> CBoxClick; //Assign OnClick event to CBoxClick
} //End of for loop
} //End of function
// Event Handler ------------------
void __fastcall TForm1::CBoxClick(TObject *Sender){
if (static_cast<TCheckBox*>(Sender)!=NULL){
Form1 -> Debug -> Text = (static_cast<TCheckBox*>(Sender) -> Name);
}
else{
Form1 -> Debug -> Text = "Object is not a TCheckBox";
}
}
来源:https://stackoverflow.com/questions/51976382/event-handler-for-dynamically-created-checkbox