I have a function that creates a button dynamically
void createBtn(News obj,TForm *Form1){
TButton *spam = new TButton(Form1);
spam->Parent = newsCard;
spam->Position->X = 280;
spam->Position->Y = 256;
spam->Text = "Spam";
}
I need to assign an OnClick
event to it, so I added the following line to the function above:
spam->OnClick = spamClick;
The code for spamClick is:
void __fastcall TForm1::spamClick(TObject *Sender, News obj)
{
allUsers[userIndex].spamNews(obj);
ShowMessage("Done!");
}
The problem is, I need to pass the obj
in the line, but the function requires 2 arguments, which are the Sender
and the obj
.
spam->OnClick = spamClick(obj); // error here
But I do not know what to pass. I've tried Form1
, spam
, and newsCard
. But nothing works.
What do I pass as a Sender
? Or, is there a way to assign an OnClick event to the button inside createBtn()
?
Edit: class News has the following definition
class News
{
public:
News(string, string, string, Dates);
string title;
string description;
Dates date;
int rate;
string category;
vector<Comment> comments;
int spamCount;
static int newsCount;
int newsID;
int numOfRatedUsers;
};
and spamNews is a function in the user class that pushes the obj.newsID into a vector in the user then increases the spamCount.
void user::spamNews(News& obj) {
//check that the news in not already spammed
if(!findNews(spammedNews,obj)){
spammedNews.push_back(obj.newsID);
obj.spamCount++;
}
}
Your second approach doesn't work, because you are trying to call spamClick()
first and then assign its return value to the OnClick
event.
Your first approach is the correct way, however you can't add parameters to the OnClick
event handler.
TButton
has Tag...
properties for holding user-defined data. However, since the News
object is not being passed around by pointer, the Tag...
properties are not very helpful in this case (unless the News
object is held in an array/list whose index can then be stored in the Tag
).
Otherwise, I would suggest deriving a new class from TButton
to hold the News
object, eg:
class TMyButton : public TButton
{
public:
News NewsObj;
__fastcall TMyButton(TComponent *Owner, const News &obj)
: TButton(Owner), NewsObj(obj) {}
};
void TForm1::createBtn(const News &obj)
{
TMyButton *spam = new TMyButton(this, obj);
spam->Parent = newsCard;
spam->Position->X = 280;
spam->Position->Y = 256;
spam->Text = _D("Spam");
spam->OnClick = &spamClick;
}
void __fastcall TForm1::spamClick(TObject *Sender)
{
MyButton *btn = static_cast<TMyButton*>(Sender);
allUsers[userIndex].spamNews(btn->NewsObj);
ShowMessage(_D("Done!"));
}
UPDATE: Since your News
objects are being stored in a vector
that you are looping through, then a simpler solution would be to pass the News
object to createBtn()
by reference and then store a pointer to that object in the TButton::Tag
property, eg:
void TForm1::createBtn(News &obj)
{
TButton *spam = new TButton(this);
spam->Parent = newsCard;
spam->Position->X = 280;
spam->Position->Y = 256;
spam->Text = _D("Spam");
spam->Tag = reinterpret_cast<NativeInt>(&obj);
spam->OnClick = &spamClick;
}
void __fastcall TForm1::spamClick(TObject *Sender)
{
TButton *btn = static_cast<TButton*>(Sender);
News *obj = reinterpret_cast<News*>(btn->Tag);
allUsers[userIndex].spamNews(*obj);
ShowMessage(_D("Done!"));
}
Or, using the TMyButton
descendant:
class TMyButton : public TButton
{
public:
News *NewsObj;
__fastcall TMyButton(TComponent *Owner)
: TButton(Owner) {}
};
void TForm1::createBtn(News &obj)
{
TMyButton *spam = new TMyButton(this);
spam->Parent = newsCard;
spam->Position->X = 280;
spam->Position->Y = 256;
spam->Text = _D("Spam");
spam->NewsObj = &obj;
spam->OnClick = &spamClick;
}
void __fastcall TForm1::spamClick(TObject *Sender)
{
MyButton *btn = static_cast<TMyButton*>(Sender);
allUsers[userIndex].spamNews(*(btn->NewsObj));
ShowMessage(_D("Done!"));
}