Delphi 如何检查表单是否已关闭?
我看到的唯一方法是为这个添加标志,但这是最好的方法吗 当表格被销毁,我检查(分配(表格2))结果是否为真?为什么?Delphi 如何检查表单是否已关闭?,delphi,forms,vcl,Delphi,Forms,Vcl,我看到的唯一方法是为这个添加标志,但这是最好的方法吗 当表格被销毁,我检查(分配(表格2))结果是否为真?为什么? 这样做的方法是什么?哇,过去的爆炸:) Assigned()的工作方式是,它基本上对指针执行nil检查。如果销毁form2,form2仍将指向一个内存地址 我已经有很长一段时间没有做任何Delphi了,但是从内存来看,当form2var被销毁时,您需要手动将它设置为nil。如果您有一个创建和销毁表单的中心位置(例如表单代理?),这应该很容易。如果您使用Form1.Free或Form
这样做的方法是什么?哇,过去的爆炸:) Assigned()的工作方式是,它基本上对指针执行nil检查。如果销毁form2,form2仍将指向一个内存地址
我已经有很长一段时间没有做任何Delphi了,但是从内存来看,当form2var被销毁时,您需要手动将它设置为nil。如果您有一个创建和销毁表单的中心位置(例如表单代理?),这应该很容易。如果您使用
Form1.Free
或Form1.destroy
,Delphi将销毁对象,但不会将对象引用设置为零。因此,请改用FreeAndNil
有关详细信息,请检查Andreas Rejbrand answer in您可以使用Form1.Showing查看表单是否已关闭
仅关闭表单不会释放它,除非在
OnClose
事件中设置Action:=caFree
。默认设置为在关闭应用程序时执行某些例程时遇到相同问题。在这种情况下,所有表单都会在后台销毁,但指针不会设置为nil。此代码帮助我:
procedure TMyForm.FormDestroy(Sender: TObject);
begin
MyForm:=nil;
end;
指针变为nil,我可以用
Assigned
检查它,或者与nil
进行比较。作为提示,在某些特殊情况下,正确的方法是创建一个计时器,将nil赋值给变量
如果你在自己的代码中创建表单MyForm:=TMyForm.create
并且你有一个MyFrom.Close
这很简单,只需添加一个MyForm:=nil
或者更好的MyForm.FreeAndNil
。。。但有时参考资料是不存在的
示例:在过程内部,在循环中创建同一表单的许多副本(或仅一个),让表单打开并结束该过程,现在对打开表单的引用不存在,因此不能以正常方式指定nil或执行freeandnil等操作
在这种情况下,诀窍是使用一个计时器(只有一毫秒)来完成,该计时器需要引用,因此您必须存储在全局上,就像对Self的引用一样,所有这些都可以在on close事件上完成
执行free(在任何地方都没有引用)的最简单方法是在主窗体上创建一个TObjectList,这样它将保存所有需要释放的窗体引用,并定义一个计时器(一毫秒),该计时器将通过该列表执行freeandnil;然后在oncose上,将Self
添加到该列表并启用该计时器
现在,在另一部分中,您有一个在开始时自动创建的普通表单,但是您需要将其设置为nil,并在您自己的代码中重新创建它
这种情况下有一个指向该表单的全局变量,所以您只需要释放和置零它,而不是(我大声说)在自己的表单代码中的任何部分,您必须在表单代码中执行(我说如果大声的话)
有时您需要释放窗体,当用户关闭窗体时,它不会显示在模式中,这种情况很复杂,但同样的技巧也是有效的,在onclose事件中,您启用一个计时器(在该窗体之外,通常在主窗体上),该计时器将释放且为零。计时器间隔可以设置为一毫秒,直到窗体完全关闭后才会运行(请记住不要使用Application.ProcessMessages,这通常是一个非常糟糕的主意)
如果您将Self设置为nil、free或自己表单中的任何内容,则可能会损坏应用程序内存(这样做完全不安全,更不用说它会吃掉ram)
释放表单(及其引用为零)的唯一方法是编写一个触发器,该触发器在表单完全关闭后执行此操作。该表单未显示为模态,是关闭它的用户
我知道如何设置操作来实现自由,但如果将其设置为零,则没有其他安全的方法
必须说明:如果在主窗体上使用计时器,请在Onclose事件中对所有计时器运行Enabled:=False
。。。否则,可能会发生奇怪的事情(不是所有情况,但有时……关于销毁应用程序和在该计时器上运行代码的竞争条件),当然,如果启用了某个计时器,则可以正确地终止或中止该计时器,等等
你的问题是一件复杂的事情。。。free和nil不是通过代码而是通过用户操作关闭的窗体
对于所有其他方面:想象一下,如果应用程序在同一时间打开了许多表单,并且所有表单都可以在同一时间与用户交互(任何人都是模态的),并且您的代码引用了其中一些表单和其他表单。。。您需要知道f用户已关闭任何表单,以避免从代码中访问该表单。除非您使用计时器,否则这不是一件小事
如果您有一个“中心”窗体(如MDI应用程序),您可以将该计时器放在主MDI窗体上,这样任何关闭的子窗体都可以被释放并为零,诀窍还是在主窗体上设置计时器
只有当你确信你可以释放所有的不可见的形式,你可以有一个定时器在主窗体上,通过所有的表单,如果可见是假的,然后调用FreeAndNil,我认为这种方式容易出错,因为如果你添加一个未来的形式,它不能被释放,而是可以隐藏…此代码将无效
始终记住,如果用户是关闭必须释放的表单的onw且为零,则代码无法检测和执行,不会启动任何事件(在表单完全关闭之后),并且在表单完全关闭之前,您甚至不能尝试释放它或取消其引用,奇怪的事情可能会发生(如果主板有多个插座,则更容易出现这种情况,如果应用程序使用线程等,也更容易出现这种情况) 所以,对于线程化的应用程序(也不是线程化的),我使用了另一种非常有效的方法,不需要定时器,但需要doublTMyForm=class(TForm)
...
public
PleaseFreeAndNilMe:=Boolean;
...
procedure TMyForm.FormCreate(Sender: TObject);
begin
PleaseFreeAndNilMe:=False;
...
end;
procedure TMyForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
...
PleaseFreeAndNilMe:=True;
end;
TForm=class(Froms.TForm)
public
PleaseFreeAndNilMe:=Boolean;
end;
procedure TForm.FormCreate(Sender:TObject);
begin
inherited Create(Sender);
PleaseFreeAndNilMe:=False;
end;
procedure TForm.FormClose(Sender:TObject;var Action:TCloseAction);
begin
PleaseFreeAndNilMe:=True;
inherited FormClose(Sender,Action);
end;
function IsNilTheForm(var TheForm: TMyForm);
begin
if nil=TheForm
then begin // The form was freed and nil
IsNilTheForm:=True; // Return value
end
else begin // The form refence is not nil, but we do not know is it has been freed or not
try
if TheForm.PleaseFreeAndNilMe
then begin // The form is not freed but wants to
try
TheForm.Free;
except
end;
try
TheForm:=Nil;
except
end;
IsNilTheForm:=True; // Return value
end
else begin // The form is not nil, not freed and do not want to be freed
IsNilTheForm:=False; // Return value
end;
except // The form was freed but not set to nil
TheForm:=Nil; // Set it to nil since it had beed freed
IsNilTheForm:=True; // Return value
end;
end;
end;