Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does my program crash when I destroy a button in its own OnClick handler?

I tried a script from a web site I run http://www.delphi-central.com/runtime.aspx and succeed.


private
  { Private declarations }
  procedure CustomButtonClick(Sender: TObject);

procedure TForm1.AddNewButtonClick(Sender: TObject);
var
  NewButton : TButton;
begin 
  NewButton := TButton.create(self);

  with NewButton do
  begin
    Top    := 30;
    Width  := 60;
    Left   := Width * (self.ControlCount-2);
    Parent := self;
    OnClick := CustomButtonClick;
    Caption := 'Button '+ inttostr (self.ControlCount-2);
  end;  //With
end;

procedure TForm1.DeleteLastButtonClick(Sender: TObject);
begin
  if Self.ControlCount>2 then
    TButton (Controls[ControlCount-1]).destroy;
end;

procedure TForm1.CustomButtonClick(Sender: TObject); 
begin    
    ShowMessage(TButton(Sender).caption + ' Pressed'); 
end;

But if I change the OnClick,

OnClick := CustomButtonClick; ==> OnClick := DeleteLastButtonClick;

it will generate an error message. How could this happen ...???

like image 338
Josef J Avatar asked Jul 29 '10 04:07

Josef J


3 Answers

Of course it goes boom--that's what's liable to happen when you cut off the branch you're sitting on.

You can't kill a control inside an event handler spawned by that control.

Note that the sample you're working from did NOT point the CustomButtonClick at the delete routine!

like image 89
Loren Pechtel Avatar answered Oct 21 '22 19:10

Loren Pechtel


An event handler is called by a function on the control's object, and it could have more code to execute once the event handler finishes. If you delete the control, then any code that references that object is likely to raise an access violation.

What you need to do is get your program to delete the control after it's done with all the code it's currently running. For that, you need to post a message. If you don't know about messages, this is a good opportunity to learn.

You need to create a new message type ID. WM_USER + 1 should work. One of the params will be the address of the control to be deleted. Set up a message handler on your form that handles that message type and frees the control referenced in the message param. And then in the event handler, have it PostMessage that message to your form. That should work without causing access violations.

like image 28
Mason Wheeler Avatar answered Oct 21 '22 18:10

Mason Wheeler


It is easy think see the reason, when you consider that the system must somehow redraw the button after you release the mouse button / key. Since you're deleting the button object already during the click, this will fail.

Hence you need to find a way to somehow delete the button after the processing of the onClick event has occurred and successfully finished.

like image 20
Schedler Avatar answered Oct 21 '22 19:10

Schedler