Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to know why 'OnCloseQuery' is called - MDI child closed or App Shutdown?

Tags:

delphi

mdi

I am currently developing an MDI application.
Every time a new MDI child window is created, it's underlying data is saved on the fly to an SQLite database and the column open is set to 1, so if the user closes the program and reopens it, the windows are restored (also in case of Anything BadTM).
So every document is always present in the database - the only thing that happens if the user clicks "Save" is that the column persistent is set to 1.
Now if an MDI child window is closed, open is set to 0 - and every row with persistent=0 AND open=0 is doomed and will be deleted.

As a result of this behaviour I don't need to ask "Save documents?" on ApplicationClose.
But I do need to ask every time an MDI child window is closed.
That would all be easy to do if Mainform.OnCloseQuery would be called before MDIChild.OnCloseQuery, but sadly that's not the case.

To sum it up:
I need a way to know whether MDIChild.OnCloseQuery is called because

  • the application is shutting down, or
  • the MDI child window is being closed.

Is there any way to do this?

like image 985
Pharaoh Avatar asked Dec 27 '12 12:12

Pharaoh


1 Answers

You need to override the protected virtual method CloseQuery in your main form. When that fires you know the app is going down. But the inherited implementation calls CloseQuery on the MDI children before firing the OnCloseQuery event on the main form.

Here is the TCustomForm implementation of CloseQuery:

function TCustomForm.CloseQuery: Boolean;
var
  I: Integer;
begin
  if FormStyle = fsMDIForm then
  begin
    Result := False;
    for I := 0 to MDIChildCount - 1 do
      if not MDIChildren[I].CloseQuery then Exit;
  end;
  Result := True;
  if Assigned(FOnCloseQuery) then FOnCloseQuery(Self, Result);
end;

Notice that the MDI children get their CloseQuery notifications before that for Self, i.e. the main form.

So in your main form you need:

type
  TMainForm = class(TForm);
  private
    FCloseQueryExecuting: Boolean;
  protected
    function CloseQuery: Boolean; override;
  public
    property CloseQueryExecuting: Boolean read FCloseQueryExecuting;
  end;

and then an implementation that looks like this:

function TMainForm.CloseQuery: Boolean; 
begin
  FCloseQueryExecuting := True;
  try
    Result := inherited CloseQuery;
  finally
    FCloseQueryExecuting := False;
  end;
end;

Then the MDI children can check the state of the main form's FCloseQueryExecuting property in their OnCloseQuery events.

like image 57
David Heffernan Avatar answered Oct 23 '22 11:10

David Heffernan