How to close an MDI child without using the system Close button
Asked Answered
L

1

5

I am using the code below to close an MDI child form by clicking on the system close button, and it works fine:

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

But how if I want to close the MDI child form by using a standard button (inside the child form itself). If I call Close within an event handler, then I get an access violation exception.

Is there any way to close the MDI child form by using a standard button (not the system close button) placed inside the child form itself, without raising an access violation exception?

I've done searching similar questions, and tried various code, but still got the exception.

Litchfield answered 25/11, 2016 at 8:12 Comment(1)
see: Why is there a special PostQuitMessage function? by Raymond Chan devblogs.microsoft.com/oldnewthing/?p=33453Acariasis
D
7

Calling Close() on a child MDI Form from inside a button OnClick event of the same child Form is perfectly safe. Internally, Close() triggers the OnClose event, and if the Action parameter is set to caFree then the Form will call Release() on itself, which is a delayed action that will free the Form from memory when it is safe to do so.

The following code works perfectly fine for me in Delphi 7:

unit ChildUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TChildForm = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  ChildForm: TChildForm;

implementation

{$R *.dfm}

procedure TChildForm.Button1Click(Sender: TObject);
begin
  Close;
end;

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

end.

If you are getting an Access Violation when calling Close(), the most likely culprit is you are calling Close() on an invalid Form pointer.

Dorkas answered 25/11, 2016 at 19:16 Comment(6)
i'm using the following earlier for the onclick: code procedure Tfrm_input.SpeedButton1Click(Sender: TObject); begin frm_input.Close(); end; it got me an exception.Litchfield
Try Self.Close instead or simpler just Close.Blanca
@AlianaDonovan clearly your frm_input variable is not pointing at a valid Form object, that would account for the AV.Dorkas
@RemyLebeau - Great answer. Raymond Chan explains more about the "delayed close" in "Why is there a special PostQuitMessage function?" devblogs.microsoft.com/oldnewthing/?p=33453Acariasis
@Rigel that is not the delayed close I was referring to. TForm.Release() posts a VCL CM_RELEASE message to the Form. When the Form receives that message at some later time, after the OnClick and OnClose event handlers have exited and no other messages are being processed, then the Form Frees itself.Dorkas
@RemyLebeau - Ok. I see. PostQuitMessage is ONLY called in TApplication.Terminate (Close on main form).Acariasis

© 2022 - 2024 — McMap. All rights reserved.