I have a problem deleting a dynamically created button in Borland C++Builder 6.
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner) {
TButton *but = new TButton(this);
but->Left = 100;
but->Top = 100;
but->OnClick = click;
Form1->InsertControl(but);
}
void __fastcall TForm1::click(TObject *Sender) {
delete Sender;
}
When I click on a created button the error "Access violation at address 40005905 in module 'rtl60.bpl', read of address 00000018" appears
I know its wrong to assign a method to button that delets it, but I really need deleting button by pressing on it
There are two bugs in your code.
the global Form1
variable has not been assigned yet when the TForm1
constructor is called, so your Form1->InsertControl(but)
statement is invalid and likely to crash. Use this->
instead of Form1->
. However, you are not suppossed to call InsertControl()
directly, set the button's Parent
property instead:
but->Parent = this;
It is not safe to delete
the Sender
of an event while the event handler is running. The RTL still needs access to the object after the handler has exited (as evident by your AccessViolation error). You will have to delay the delete
, such as with a short timer:
void __fastcall TForm1::DeleteButtonTimerElapsed(TObject *Sender)
{
TObject *obj = reinterpret_cast<TObject*>(DeleteButtonTimer->Tag);
DeleteButtonTimer->Tag = 0;
DeleteButtonTimer->Enabled = false;
delete obj;
}
void __fastcall TForm1::click(TObject *Sender)
{
DeleteButtonTimer->Tag = reinterpret_cast<int>(Sender);
DeleteButtonTimer->Enabled = true;
}
Or post a custom message to yourself using PostMessage()
(I prefer this approach):
#define WM_DELETE_OBJECT (WM_USER + 1)
void __fastcall TForm1::WndProc(TMessage &Message)
{
if (Message.Msg == WM_DELETE_OBJECT)
delete reinterpret_cast<TObject*>(Message.LParam);
else
TForm::WndProc(Message);
}
void __fastcall TForm1::click(TObject *Sender)
{
TButton *btn = static_cast<TButton*>(Sender);
btn->OnClick = NULL;
PostMessage(Handle, WM_DELETE_OBJECT, 0, reinterpret_cast<LPARAM>(Sender));
}