7

I only kept main form in auto-create forms and removed the rest. Basically I call those forms with

TMyForm.Create(Self).Show;

But when my works are done with this form, how can I release the resources this form used with best way? I looked up Free, Action.CaFree, Destroy, FreeAndNil functions but I can't get it all.

I'm looking for best practices.

Thanks.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Tak Kovac
  • 83
  • 6
  • The answer is that it depends on lots of things. I'd probably start by knowing what framework I was using. Apparently you use FMX and VCL. Then you need to decide what sort of form it is, and who invokes it closing. – David Heffernan May 27 '20 at 15:28

2 Answers2

17

This depends entirely on how the form is used.

Modal forms

The simplest case is when the form is modal. Then you typically use the following idiom:

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

Or, if you want to do some special processing if the user closes the dialog box by clicking the OK button (and not the Cancel button):

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;

Notice that I use Self as owner in both cases. That isn't necessary for the sake of ownership, since -- quite obviously -- we free the forms as soon as they are closed. But I often use Self anyway, because I tend to use Position = poOwnerFormCenter for my dialogs.

Independent windows that are freed when you close them

Another particularly simple case is when you dynamically create (possibly multiple) instances of a form class and want to display them on-screen in a non-modal fashion until the user closes them, in which case the instances are freed. If so, it is really simple:

procedure TForm1.Button1Click(Sender: TObject);
var
  ImageViewer: TImageViewerFrm;
begin
  ImageViewer := TImageViewerFrm.Create(nil);
  ImageViewer.Image := 'flower.jpg';
  ImageViewer.Show;
end;

assuming it has a public property named Image that takes the file name of an image file to display.

This will create and show the form when you click the button. To make sure it is freed when you close it, just add an OnClose handler to the TImageViewerFrm and set the Action parameter to caFree:

procedure TImageViewerFrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

Using this approach, you can create any number of image viewer forms with different images, and they will all live until the user closes them, or until the application is terminated.

Other approaches

Of course, there are many more possible scenarios, and, therefore, many more possible solutions. In some cases you might want to have full control over the forms of a particular type, and so you store them in an array. It is fine to free them using MyForm.Free or FreeAndNil(ImageForms[4]).

FreeAndNil(X) effectively does X.Free; X := nil (but in a safer manner), that is, it sets the variable to nil after it has freed the object it used to point to. That way you avoid a dangling pointer. In some cases, you must do this. (But now I am digressing. This applies to Delphi objects in general, and has nothing to do with forms in particular.)

But in Delphi you never free an object (a form or not) by writing X.Destroy. You use X.Free which effectively does if X <> nil then X.Destroy.

If you want to learn more about this, I strongly recommend buying a good textbook about Delphi programming. There's no more efficient way of really learning it.

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
1

if you are creating a form and you want it to free itself up after closing then in the ONCLOSE event write action := cafree;

this way you won't have to use TRY ... Finally block to free it up.

Tony Hanna
  • 91
  • 6