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

3

5

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 ...???

Disoperation answered 29/7, 2010 at 4:51 Comment(6)
If you want to destroy a building - will you do it inside or outside?Periphrasis
Having your very first question downvoted can be very discouraging. Is this question really "unclear or not useful"?Verbal
@josef: Mason's answer is right; you can look at TForm (in Forms.pas) how it does similar things; look for the procedures Release and CMRelease, and the constant CM_Release.Metencephalon
Maybe someone downvoted because they had a hard time understanding why someone would ask this question, after a hard experience failed to educate this person that they are doing something fundamentally wrong.Yuki
Incidentally WHY are you destroying the button instead of hiding it?Yuki
Just a guess, but: perhaps it was downvoted because of that generally annoying way in which far too many people expect help... "I got an error message." (Note the full stop at the end of the sentence.) TIP for all people posting questions: if your question concerns an error message, please be kind and gracious enough to let us know what the message is!Unlovely
S
5

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!

Sosthina answered 29/7, 2010 at 5:1 Comment(3)
I think I know what you mean, can you give a little script, so I better understand?Disoperation
A script for what? The issue is you're doing something that can't be done, period. Look at Mason's answer for a way to do it correctly.Sosthina
Let me put it to you this way Josef: Please enter a phone booth, then while you are inside the phone booth, please give the order to have a ten tonne weight dropped on the phone booth. Now do you understand?Yuki
I
5

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.

Ixion answered 29/7, 2010 at 12:57 Comment(5)
Thanks Wheeler.. OK, what do you mean "new message type ID"?? maybe you can give me a little script that I more understood.Disoperation
If I just post a code sample for you to copy and paste, you won't actually learn anything about using messages, and then you won't know what to do the next time posting a message might come in handy. That's why StackOverflow is really not a "please give me working code" site. It's really pretty simple if you look it up, and I've given you everything you'll ned once you understand the principles involved.Ixion
Now I know what you mean it, I get an article on who you mean "cryer.co.uk/brian/delphi howto_send_custom_window_message.htm" I have learned more thanks so much...Disoperation
@josef: That's a pretty good article. One mistake, though. SendMessage does not post the message to the end of the message queue; it sends it directly to the recipient to be executed immediately. But aside from that mistake it looks like a good article. What you want in this case is PostMessage, which will wait until all the other messages (some of which might need to use the button) are finished before processing the new one.Ixion
Thanks for your advice. Mason, you seem to understand many things about Delphi. Maybe you can suggest to me, a book / web site what is good for me to learn?Disoperation
S
1

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.

Selfeffacement answered 29/7, 2010 at 13:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.