2007. január 22., hétfő
Free a parent form when its child gets closed or freed
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;
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése