在Delphi中销毁一个表单的正确方法是什么?

7
我只保留了自动生成表单中的主要表单,并删除了其余表单。基本上,我使用以下方式调用这些表单:
TMyForm.Create(Self).Show;

但是当我的工作使用这个表单完成后,我应该用最好的方式释放这个表单所使用的资源?我查阅了Free,Action.CaFree,Destroy,FreeAndNil函数,但我无法理解它们。

我正在寻找最佳实践。

谢谢。


答案是取决于很多事情。我可能会从了解我正在使用的框架开始。显然,您使用FMX和VCL。然后,您需要决定它是什么类型的表单,以及谁调用它关闭。 - David Heffernan
2个回答

18

这完全取决于表单的使用方式。

模态表单

最简单的情况是表单是模态的。然后通常使用以下习惯用法:

procedure TForm1.btnFrogPropertiesClick(Sender: TObject);
var
  Frm: TFrogPropertiesForm;
begin
  Frm := TFrogPropertiesForm.Create(Self);
  try
    Frm.ShowModal;
  finally
    Frm.Free;
  end;
end;

或者,如果您希望在用户通过点击 OK 按钮(而不是取消按钮)关闭对话框时执行某些特殊处理:

procedure TForm1.btnFrogPropertiesClick(Sender: TObject);
var
  Frm: TFrogPropertiesForm;
begin
  Frm := TFrogPropertiesForm.Create(Self);
  try
    if Frm.ShowModal = mrOk then
      UpdateFrog;
  finally
    Frm.Free;
  end;
end;

请注意,我在两种情况下都使用 Self 作为所有者。这并非出于所有权的考虑,因为显然我们会在关闭表单时释放它们。但我通常仍然使用 Self,因为我倾向于在我的对话框中使用 Position = poOwnerFormCenter

独立窗口,在关闭时释放

另一个特别简单的情况是,当您动态创建(可能是多个)表单类的实例并希望以非模态方式在屏幕上显示它们,直到用户关闭它们时,这些实例将被释放。如果是这样,那么非常简单:

procedure TForm1.Button1Click(Sender: TObject);
var
  ImageViewer: TImageViewerFrm;
begin
  ImageViewer := TImageViewerFrm.Create(nil);
  ImageViewer.Image := 'flower.jpg';
  ImageViewer.Show;
end;
假设它具有名为Image的公共属性,该属性接受要显示的图像文件的文件名。
单击按钮将创建并显示该表单。为确保在关闭时释放它,只需向TImageViewerFrm添加一个OnClose处理程序,并将Action参数设置为caFree:
procedure TImageViewerFrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

使用这种方法,您可以创建任意数量的图像查看器表单,它们具有不同的图像,并且它们将一直存在,直到用户关闭它们或应用程序终止。

其他方法

当然,还有许多其他可能的情况和解决方案。在某些情况下,您可能希望完全控制特定类型的表单,因此您将它们存储在数组中。可以使用MyForm.FreeFreeAndNil(ImageForms[4]) 释放它们。

FreeAndNil(X) 实际上执行了 X.Free; X := nil(但以更安全的方式),即在释放原来指向的对象之后将变量设置为nil。这样可以避免悬挂指针。在某些情况下,您必须这样做。(但现在我正在岔开话题。这适用于Delphi对象,而不是特定的表单。)

但是在Delphi中,您永远不会通过编写 X.Destroy 来释放对象(无论是表单还是其他)。您使用 X.Free,它实际上执行 if X <> nil then X.Destroy

如果您想了解更多信息,我强烈建议购买一本关于Delphi编程的好书。这是真正学习它的最有效方法。


在 "ImageViewer := TImageViewerFrm.Create(nil)" 中,参数应该是 Self 或 Application 吗?否则,应用程序如何知道这个窗体(以关闭它)。 - undefined
@GabrielM:两种方法都是有效的,但它们的行为方式不同。如果传入nil,窗口将保持打开直到用户关闭它。如果传入Self,窗口将保持打开直到用户关闭它或者Self被销毁。这可能是需要的,也可能不是。 - undefined
关于您的更新评论:“Application”的作用类似于“nil”,但是当应用程序终止时,表单将自动销毁。这确实是一个好主意(但通常并不是真正必要的,因为您的应用程序即将终止)。 - undefined

1

如果你正在创建一个表单,希望在关闭后自动释放它,则可以在 ONCLOSE 事件中写入 action := cafree;

这样就不必再使用 TRY...FINALLY 块来释放它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接