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:
procedure TMyForm.OkButtonClick(Sender: TButton);
begin
// check data...
if (data is valid) then
begin
Close() // or ModalResult := mrOk, if shown modally
end else
begin
// ModalResult := mrNone, if shown modally
ShowMessage('Error');
end;
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:
type
TCloseReason = (NotClosing, OkClicked, CancelClicked, WindowClosing, ShuttingDown);
...
private
CloseReason: TCloseReason;
...
procedure TMyForm.OkButtonClick(Sender: TObject);
begin
CloseReason := OkClicked;
Close; // or ModalResult := mrOk;
end;
procedure TMyForm.CancelButtonClick(Sender: TObject);
begin
CloseReason := CancelClicked;
Close; // or ModalResult := mrCancel;
end;
procedure TMyForm.WndProc(var Message: TMessage);
begin
if (Message.Msg = WM_SYSCOMMAND) and ((Message.WParam and $FFF0) = SC_CLOSE) then
CloseReason := WindowClosing;
else if (Message.Msg = WM_QUERYENDSESSION)
CloseReason := ShuttingDown;
inherited;
end;
procedure TMyForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if (CloseReason = OkClicked) then
begin
// check data...
if (data is not valid) then
begin
ShowMessage('Error');
CanClose := False;
CloseReason := NotClosing;
Exit;
end;
end;
CanClose := True;
end;
Alternatively:
...
private
ValidateNeeded: Boolean;
...
procedure TMyForm.OkButtonClick(Sender: TObject);
begin
ValidateNeeded := True;
Close;
end;
procedure TMyForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if ValidateNeeded then
begin
ValidateNeeded := False;
// check data...
if (data is not valid) then
begin
ShowMessage('Error');
CanClose := False;
Exit;
end;
end;
CanClose := True;
end;