Free a parent form when its child gets closed or freed (Views: 300)
Problem/Question/Abstract: I am using a TPageControl and show some forms on its pages. So, whenever I want to show a form I create a new page on the TPageControl for that form and then displat the form in that page. Now I want free that page when the user closes the form sitting on it. I tried using the form's OnClose or OnDestroy events to free the parent tabsheet of the form but I get an access violation. Answer: Solve 1: It is difficult enough to destroy a control from an event handler of that control, trying to destroy its parent adds even more problems to that. The best way to handle this is to leave the destruction of the tabsheet to a neutral 3rd party, in this case the form holding the pagecontrol. In the embedded forms OnClose you post (via postmessage) a custom message to the form holding the pagecontrol and then hide the embedded form. The host form then destroys the tabsheet and that also destroys the embedded form. Posting the message delays the action long enough to allow any code in the embedded form to complete safely. Example: {Unit for the embedded form} unit Unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; const UM_KILLCONTROL = WM_USER + 666; type TUMKillControl = record msg: Cardinal; control: TControl; unused: LPARAM; result: LRESULT; end; type TForm2 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private public end; implementation {$R *.dfm} procedure TForm2.Button1Click(Sender: TObject); begin close end; procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin action := caHide; PostMessage(GetParentForm(self).Handle, UM_KILLCONTROL, Integer(parent), 0); end; end. {Unit for the host form} unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, unit2; type TForm1 = class(TForm) StatusBar: TStatusBar; Button1: TButton; PageControl1: TPageControl; procedure Button1Click(Sender: TObject); private { Private declarations } procedure UMKillControl(var msg: TUMKillControl); message UM_KILLCONTROL; public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var tab: TTabSheet; begin tab := TTabSheet.Create(self); tab.PageControl := pagecontrol1; with TForm2.create(self) do begin borderstyle := bsNone; parent := tab; tab.caption := caption; align := alclient; show; end; end; procedure TForm1.UMKillControl(var msg: TUMKillControl); begin msg.control.Free; end; end. Solve 2: As long as the child form is not "owned" by the tabsheet on which it is parented (being owned by the form which owns the PageControl is OK), you can do this: { ... } type TfNastyChild = class(TForm) procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } fKillParent: TWinControl; public { Public declarations } destructor Destroy; override; end; implementation {$R *.dfm} procedure TfNastyChild.FormClose(Sender: TObject; var Action: TCloseAction); begin if (Parent is TTabsheet) and (Owner <> Parent) then begin Hide; fKillParent := Parent; Parent := nil; end; action := caFree; end; destructor TfNastyChild.Destroy; begin if assigned(fKillParent) and not (csDestroying in fKillParent.ComponentState) then fKillParent.Free; inherited; end; |