4
votes

Basically, I'm using a TTimer event to close all the open forms and bring the user back to the main form. I could iterate through Screen.Forms:

for i := 0 to Screen.Formcount - 1 do
  Screen.Forms[i].close;

The problem is the OnCloseQuery events on some of those forms - they pop up MessageDlg's which interrupt this process :(

2
I'm trying to avoid having to 'hack' the 'OnCloseQuery' event of all the forms. Also, when a MessageDlg pops up, this can count as a 'new' form, which was not in the "close" loop before, so it has to be closed manually.Richard Woolf
If they're interrupting the process for a reason, then they shouldn't be closed. If there's no reason for them to not to close then they shouldn't be interrupting the process (they shouldn't set 'CanClose').Sertac Akyuz
The OnCloseQuery events frequently contain MessageDlgs saying "Are you sure you want to cancel this activity?" Yes / No --I don't want to even offer them such a choice -- I want to close, without OnCloseQuery.Richard Woolf
So you're asking the user if there's a reason for not to close. I would just be sure that there's a visual indication that there's an activity and leave the rest to the user. But maybe that's just me..Sertac Akyuz
Seems like you need to refactor your app. "Close handling logic" could be delegated to a single place that has all the information it needs. Much nicer than a global boolean hack.Warren P

2 Answers

7
votes

You can use a flag in your main form that your other forms would check before asking the user whether to proceed or not. Something like this:

unit1

type
  TForm1 = class(TForm)
    ..
  public
    UnconditinalClose: Boolean;
  end;

..

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  UnconditinalClose := True;
end;

unit 2:

implementation

uses
  unit1;

procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := unit1.Form1.UnconditinalClose;
  if not CanClose then
    // ask the user if he/she's sure he/she wants to close
end;


One other solution could be detaching OnCloseQuery event handlers of other forms. This would only be practical if these other forms are released (freed) when closing, not hidden (edited to reflect Rob's comment):

procedure TForm1.Timer1Timer(Sender: TObject);
var
  i: Integer;
  SaveHandler: TCloseQueryEvent;
begin
  for i := 0 to Screen.Formcount - 1 do
    if Screen.Forms[i] <> Self then begin
      SaveHandler := Screen.Forms[i].OnCloseQuery;
      Screen.Forms[i].OnCloseQuery := nil;
      Screen.Forms[i].Close;
      Screen.Forms[i].OnCloseQuery := SaveHandler;
    end;
end;
-1
votes
for i := 1 to Screen.Formcount - 1 do
  Screen.Forms[i].close;

Initial the value i with 1, not 0.