Recent

Author Topic: How to get form returned value in OnCloseQuery event?  (Read 901 times)

artem101

  • Jr. Member
  • **
  • Posts: 84
How to get form returned value in OnCloseQuery event?
« on: June 07, 2022, 10:24:46 pm »
For example, I have dialog form with TButtonPanel with Ok and Cancel buttons. When user press Ok button I need to check the entered data. If it is incorrect error message would be show and CanClose variable in OnCloseQuery event would be set to False to prevent form closure and let user to fix data. Of course for pressing Cancel button or closing window with [X] button no checks are needed.
« Last Edit: June 07, 2022, 10:27:03 pm by artem101 »

HeavyUser

  • Sr. Member
  • ****
  • Posts: 397
Re: How to get form returned value in OnCloseQuery event?
« Reply #1 on: June 08, 2022, 12:20:31 am »
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  2. var
  3.   Frm : TForm1;
  4. begin
  5.   if sender is TForm1 then begin
  6.     CanClose := true;
  7.     Frm := TForm1(Sender);
  8.     CanClose := CanClose and Valid(Frm.edTaxID.text)
  9.                          and Valid(Frm.edZipCode.text)
  10.     .
  11.     .
  12.     .
  13.                          and Valid(Frm.edVatID.text);
  14.   end;
  15. end;
« Last Edit: June 08, 2022, 12:22:49 am by HeavyUser »

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1314
    • Lebeau Software
Re: How to get form returned value in OnCloseQuery event?
« Reply #2 on: June 08, 2022, 06:40:18 pm »
When user press Ok button I need to check the entered data. If it is incorrect error message would be show and CanClose variable in OnCloseQuery event would be set to False to prevent form closure and let user to fix data. Of course for pressing Cancel button or closing window with [X] button no checks are needed.

The OnCloseQuery event is not the best place to do that validation (especially if the Form is shown modally, because not all close routes will even trigger OnCloseQuery in that situation).  Unless you manually keep track of the Form's state (especially state based on system messages) then you won't know WHY the event is being fired, so you won't be able to make informed decisions at that time.  Did the user click on the Ok clicked? The Cancel button? The X button? Is the OS being shutdown? There are many possible reasons WHY the OnCloseQuery event is fired (or not fired at all).

You should do the validation in the Ok button's OnClick handler instead.  If the validation fails, simply don't close the Form:

Code: Pascal  [Select][+][-]
  1. procedure TMyForm.OkButtonClick(Sender: TButton);
  2. begin
  3.   // check data...
  4.   if (data is valid) then
  5.   begin
  6.     Close() // or ModalResult := mrOk, if shown modally
  7.   end else
  8.   begin
  9.     // ModalResult := mrNone, if shown modally
  10.     ShowMessage('Error');
  11.   end;
  12. end;

Otherwise, if you absolutely must use the OnCloseQuery event (which I don't recommend in this situation), then you would need something like this:

Code: Pascal  [Select][+][-]
  1. type
  2.   TCloseReason = (NotClosing, OkClicked, CancelClicked, WindowClosing, ShuttingDown);
  3. ...
  4. private
  5.   CloseReason: TCloseReason;
  6. ...
  7. procedure TMyForm.OkButtonClick(Sender: TObject);
  8. begin
  9.   CloseReason := OkClicked;
  10.   Close; // or ModalResult := mrOk;
  11. end;
  12.  
  13. procedure TMyForm.CancelButtonClick(Sender: TObject);
  14. begin
  15.   CloseReason := CancelClicked;
  16.   Close; // or ModalResult := mrCancel;
  17. end;
  18.  
  19. procedure TMyForm.WndProc(var Message: TMessage);
  20. begin
  21.   if (Message.Msg = WM_SYSCOMMAND) and ((Message.WParam and $FFF0) = SC_CLOSE) then
  22.     CloseReason := WindowClosing;
  23.   else if (Message.Msg = WM_QUERYENDSESSION)
  24.     CloseReason := ShuttingDown;
  25.   inherited;
  26. end;
  27.  
  28. procedure TMyForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  29. begin
  30.   if (CloseReason = OkClicked) then
  31.   begin
  32.     // check data...
  33.     if (data is not valid) then
  34.     begin
  35.       ShowMessage('Error');
  36.       CanClose := False;
  37.       CloseReason := NotClosing;
  38.       Exit;
  39.     end;
  40.   end;
  41.   CanClose := True;
  42. end;
  43.  

Alternatively:

Code: Pascal  [Select][+][-]
  1. ...
  2. private
  3.   ValidateNeeded: Boolean;
  4. ...
  5. procedure TMyForm.OkButtonClick(Sender: TObject);
  6. begin
  7.   ValidateNeeded := True;
  8.   Close;
  9. end;
  10.  
  11. procedure TMyForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  12. begin
  13.   if ValidateNeeded then
  14.   begin
  15.     ValidateNeeded := False;
  16.     // check data...
  17.     if (data is not valid) then
  18.     begin
  19.       ShowMessage('Error');
  20.       CanClose := False;
  21.       Exit;
  22.     end;
  23.   end;
  24.   CanClose := True;
  25. end;
  26.  
« Last Edit: June 08, 2022, 07:09:03 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1314
    • Lebeau Software
Re: How to get form returned value in OnCloseQuery event?
« Reply #3 on: June 08, 2022, 06:47:32 pm »
Code: Pascal  [Select][+][-]
  1. CanClose := CanClose and Valid(Frm.edTaxID.text)
  2.                      and Valid(Frm.edZipCode.text)
  3.     .
  4.     .
  5.     .
  6.                      and Valid(Frm.edVatID.text);

That code is not trying to differentiate between pressing the Ok button vs the Cancel/X buttons, like the OP asked for.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

HeavyUser

  • Sr. Member
  • ****
  • Posts: 397
Re: How to get form returned value in OnCloseQuery event?
« Reply #4 on: June 09, 2022, 09:14:20 pm »
Code: Pascal  [Select][+][-]
  1. CanClose := CanClose and Valid(Frm.edTaxID.text)
  2.                      and Valid(Frm.edZipCode.text)
  3.     .
  4.     .
  5.     .
  6.                      and Valid(Frm.edVatID.text);

That code is not trying to differentiate between pressing the Ok button vs the Cancel/X buttons, like the OP asked for.
True! I just thought that setting a flag to true for the ok button press is trivial enough, but my recommendation when asked would be to just move the code to the ok button's onclick event, that would have solved most logical problems.

 

TinyPortal © 2005-2018