Title: How do I free a dynamically created object by clicking an object on it?
Say you have a dynamically created TPanel and on that panel you have a button that the user can use to close (TPanel.Free;) that panel.
Let's call the Panel myPanel. You cannot close myPanel by simply putting myPanel.Free; in the onClick event. This is because the button's event is executing and it will result in an EAccessViolation or an EAbstractError.
So how do you do this then? Well, that requires using a different procedure than the TButton.OnClick event.
You can do this by using PostMessage:
First you declare a constant that allows you to identify the message that will cause the procedure to trigger
CODE
// Declare your message that your app will respond to
const CW_FREEPANEL = WM_USER + WM_APP + 123;
type
TForm1 = class(TForm)
Here you tell your app that when a message with CW_FREEPANEL as the constant arrives, that it will need to execute this procedure
CODE
{ private declarations }
// Declare the procedure that will respond to CW_FREEPANEL
procedure FreeThisPanel(var msg: TMessage); message CW_FREEPANEL;
Here you define what happens once the message is received. In this case you free the panel.
CODE
procedure TForm1.FreeThisPanel(var Msg: TMessage);
begin
// Reads out WParam to know which panel to free
TTabSheet(msg.WParam).Free;
end;
With PostMessage you can set this message in the windows message queu so your app can respond to it. The user clicks on the button and the button onclick event will then post a message that your application can use to free it. By using
(Sender as TButton).Parent
you get the parent object which you pass on to the procedure that will free it.
CODE
procedure TForm1.thisButton(Sender: TObject);
begin
// Posts the message with the offending panel in WParam
PostMessage(Self.Handle, CW_FREEPANEL, integer((Sender as TButton).Parent), 0);
end;
This gave me a lot of headaches so I thought I would post it here and hopefully prevent others from suffering from this as well.