type TForm1 = class(TForm) Memo1: TMemo; Button1: TButton; Button2: TButton; Button3: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } public { Public declarations } end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin Action:=caFree; end;
procedure TForm1.Button1Click(Sender: TObject); begin with TForm.Create(Self) do begin OnClose := FormClose; Show; end; end;
procedure TForm1.Button2Click(Sender: TObject); var I: Integer; begin Memo1.Lines.Clear; for I := 0 to Screen.FormCount - 1 do begin if Screen.Forms[I] <> Self then Memo1.Lines.Add(Screen.Forms[I].ClassName); end; end;
procedure TForm1.Button3Click(Sender: TObject); var I: Integer; begin for I := 0 to Screen.FormCount - 1 do begin if Screen.Forms[I] <> Self then Screen.Forms[I].Show; end; end;
上代码: 前提代码: procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := TCloseAction.caFree; end;
procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := TCloseAction.caFree; end;
正式代码: procedure TForm1.Button1Click(Sender: TObject); var i: Integer; begin Memo1.Lines.Add(Application.ComponentCount.ToString); Memo1.Lines.Add('MainForm: ' + Application.MainForm.Name);
for I := 0 to Application.ComponentCount -1 do begin if (Application.Components[i] is TForm) then begin Memo1.Lines.Add(Application.Components[i].Name); end; end; end;
procedure TForm1.Button2Click(Sender: TObject); begin Form2.Show; Form3.Show; end;
我假设保存的代码在这些 Form 里面(实际上不应该在这里面,数据处理的代码应该单独放到一个 TDataModule 里面去);我假设你的每个 Form 都有一个相同的公共方法叫做 SaveMe;
在程序退出之前执行:
for I := 0 to Application.ComponentCount -1 do begin if (Application.Components[i] is TForm2) then begin TForm2(Application.Components[i]).SaveMe; end else if (Application.Components[i] is TForm3) then begin TForm3(Application.Components[i]).SaveMe; end; end;
for I := 0 to Application.ComponentCount -1 do begin if (Application.Components[i] is TForm) then begin if supports( Application.Components[i], XXX, TMyInterface) then begin (Application.Components[i] as TMyInterface).SaveMe; end; end; end;
问题也来了,如上面所说的,“子窗口”没关,直接关主窗口,这时,各个“子窗口”会直接消失,不会发生 Close 事件,数据就无法保存。
所以,我想在主窗口关闭时,通知“子窗口”关闭,保存数据。由于各个“子窗口”是自销毁,即关闭就自动销毁自己,所以我原本是没有保留“子窗口”的指针的,主窗口只负责创建“子窗口”,其他的一概不管。但现在需要通知“子窗口”保存数据了,所以我建了个 TForm 数组 FormList:TArray<TForm>,保留各“子窗口”,在主窗口 Close 事件里: for i:=Low(FormList) to High(FormList) do if Assigned(FormList[i]) then FormList[i].Close; 这样先挨个关闭“子窗口”,可以保存数据。
it's not necessary create any list for take care of your sub-forms ---------- for "Close" your sub-forms, dont use any procedure where the user should be "questioned": Close or Not Close this form?
----------
frmFormSecond.COMPONENTS / COMPONENTSCOUNT can be used to find your form desired!
---------- var frmFormSecond: TfrmFormSecond;
implementation
{$R *.dfm}
procedure TfrmFormSecond.btn_Creating_FormsClick(Sender: TObject); var lMyNewForm: TForm; begin lMyNewForm := TForm.Create(nil); // or (Self); try // // all components will be "automatically" destroyed // frmFormSecond.InsertComponent(lMyNewForm); // Component should be "no-name", or, "name-unique" <> others components on Form!!! // if not(lMyNewForm.Owner = nil) then lMyNewForm.Caption := 'Owner = ' + lMyNewForm.Owner.Name; // lMyNewForm.Show; // or ShowModal ... but...
type TForm1 = class(TForm) Button1: TButton; Button2: TButton; private { Private declarations } procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND; public { Public declarations } end;
var Form1: TForm1;
implementation
{$R *.dfm}
uses Unit2;
{ TForm1 }
procedure TForm1.WMSysCommand(var Msg: TWMSysCommand); begin if Msg.CmdType = SC_CLOSE then ShowMessage('OK'); inherited; end;
----------------------------------------------
-
IList<T> = interface procedure Clear; function Add(const Value: T): Integer; function Remove(const Value: T): Integer; procedure Delete(Index: Integer); function IndexOf(const Value: T): Integer; procedure Sort(const AComparer: IComparer<T>); function GetEnumerator: TList<T>.TEnumerator;
function GetCount: Integer; property Count: Integer read GetCount;
function GetItem(Index: Integer): T; procedure SetItem(Index: Integer; Item: T); property Items[Index: Integer]: T read GetItem write SetItem; default; end;
TListIntf<T> = class class function Create: IList<T>; end;
TInterfacedList<T> = class(TList<T>, IList<T>) private const objDestroyingFlag = Integer($80000000); function GetRefCount: Integer; inline; protected [Volatile] FRefCount: Integer; class procedure __MarkDestroying(const Obj); static; inline; function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; property RefCount: Integer read GetRefCount;
function GetCount: Integer; function GetItem(Index: Integer): T; procedure SetItem(Index: Integer; Value: T); public procedure AfterConstruction; override; procedure BeforeDestruction; override; class function NewInstance: TObject; override;
function TInterfacedList<T>.GetRefCount: Integer; begin Result := FRefCount and not objDestroyingFlag; end;
class procedure TInterfacedList<T>.__MarkDestroying(const Obj); var LRef: Integer; begin repeat LRef := TInterfacedList<T>(Obj).FRefCount; until AtomicCmpExchange(TInterfacedList<T>(Obj).FRefCount, LRef or objDestroyingFlag, LRef) = LRef; end;
procedure TInterfacedList<T>.AfterConstruction; begin // Release the constructor's implicit refcount AtomicDecrement(FRefCount); end;
procedure TInterfacedList<T>.BeforeDestruction; begin if RefCount <> 0 then System.Error(reInvalidPtr); end;
// Set an implicit refcount so that refcounting during construction won't destroy the object. class function TInterfacedList<T>.NewInstance: TObject; begin Result := inherited NewInstance; TInterfacedList<T>(Result).FRefCount := 1; end;
function TInterfacedList<T>.QueryInterface(const IID: TGUID; out Obj): HResult; begin if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE; end;
function TInterfacedList<T>._AddRef: Integer; begin Result := AtomicIncrement(FRefCount); end;
function TInterfacedList<T>._Release: Integer; begin Result := AtomicDecrement(FRefCount); if Result = 0 then begin // Mark the refcount field so that any refcounting during destruction doesn't infinitely recurse. __MarkDestroying(Self); Destroy; end; end;
procedure TForm1.FormCreate(Sender: TObject); begin ReportMemoryLeaksOnShutDown := True; FormList := TListIntf<TForm>.Create; Position := poScreenCenter; Id := 2; end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin Action:=caFree; FormList.Remove(TForm(Sender)); end;
procedure TForm1.Button1Click(Sender: TObject); var Form: TForm; begin Form := TForm.Create(Self); Form.OnClose := FormClose; FormList.Add(Form); Form.Name := 'Form' + Id.ToString; Inc(Id); Form.Show; end;
procedure TForm1.Button2Click(Sender: TObject); var Form: TForm; begin Memo1.Lines.Clear; for Form in FormList do begin Memo1.Lines.Add(Form.Name + ': ' + Form.ClassName); end; end;
procedure TForm1.Button3Click(Sender: TObject); var Form: TForm; begin for Form in FormList do begin Form.Show; end; end;