tags:

views:

108

answers:

2

Hello,

I have a button. Its OnClick event calls a procedure which destroys the button, but then the "thread" wants to return to the OnClick event and I get an access violation.

I'm completely stumped!

+1  A: 

You could instead just enable a timer in the OnClick event, then write the Timer event first to disable the timer and then call the procedure you are currently calling from the OnClick event. Set up the timer disabled and with a short interval time.

frogb
+8  A: 

You need to destroy the button after all its code is finished executing. The standard way to do this is by posting a user-defined message to the form and giving the form a message method that will interpret it. For example:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

const
  WM_KILLCONTROL = WM_USER + 1;

type

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    procedure KillControl(var message: TMessage); message WM_KILLCONTROL;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  PostMessage(self.Handle, WM_KILLCONTROL, 0, integer(Button1))
end;

procedure TForm1.KillControl(var message: TMessage);
var
  control: TControl;
begin
  control := TObject(message.LParam) as TControl;
  assert(control.Owner = self);
  control.Free;
end;

end.

This works because the message gets put into the Windows Message Queue and doesn't come out until everything before it (including the Click message that the button is currently responding to) is finished processing.

Mason Wheeler
This worked nicely, thanks! I had tried to do a "SendMessage" but it didn't work, so I gave up on this approach. "PostMessage" did the trick!
Pmmlr
@Pmmlr: Yeah. SendMessage processes the message immediately, while PostMessage posts it to the message queue so it has to wait its turn before processing.
Mason Wheeler
@Pmmlr: This is same way as `procedure TForm.Release` has been doing since Delphi 1: `PostMessage(Handle, CM_RELEASE, 0, 0);` it works together with the `procedure TForm.CMRelease` which does `Free`, Knowing the difference between `PostMessage` and `SendMessage` is important: it is why it works. This question explains PostMessage in more detail: http://stackoverflow.com/questions/2551435/postmessage-tutorial
Jeroen Pluimers