Lazarus

Programming => LCL => Topic started by: Aidex on November 12, 2017, 11:27:44 am

Title: BitBtn bkClose closes window even though ModalResult is mrNone. Bug or feature?
Post by: Aidex on November 12, 2017, 11:27:44 am
Hello!
I've placed a TBitBtn on a form, choose bkClose kind, but want to handle OnClick myself, so I've set the button's modalresult to mrNone.
I hoped mrNone would prevent automatically closing the form, but the window closes before I can handle the button's OnClick event.
As I understood mrNone, it shouldn't close a form.
Title: Re: BitBtn bkClose closes window even though ModalResult is mrNone. Bug or feature?
Post by: wp on November 12, 2017, 11:38:03 am
You must set the ModalResult of the Form to prevent the form from closing.
Title: Re: BitBtn bkClose closes window even though ModalResult is mrNone. Bug or feature?
Post by: Aidex on November 12, 2017, 11:48:35 am
Form's ModalResult is mrNone! (default)
There's no change when I set Form.ModalResult:=mrNone at runtime or in BitBtn.OnClick() event.
The form will be closed anyway!
Title: Re: BitBtn bkClose closes window even though ModalResult is mrNone. Bug or feature?
Post by: wp on November 12, 2017, 11:55:22 am
It *is* working - I do this all the time for error checking before a form can close. See attached demo.

Maybe my description was too short: you must use the OnClick event of the form to set its ModalResult to mrNone in order to prevent closing of the form. Having clicked on the OKButton has changed the form's Modalresult to the ModalResult of the button. Therefore, the form closes when the OnClick handler exits. Setting the form's ModalResult back to mrNone prevents closing the form.
Title: Re: BitBtn bkClose closes window even though ModalResult is mrNone. Bug or feature?
Post by: Aidex on November 12, 2017, 12:07:35 pm
Oh yes, in your example it's working - because the button is not on the main form.
But in my program the button is on Form1 and it always closes the program.  :(
I can reproduce it in your example program, too, when I copy the button from Form2 to Form1
(also after setting button's ModalResult to mrNone)
Title: Re: BitBtn bkClose closes window even though ModalResult is mrNone. Bug or feature?
Post by: wp on November 12, 2017, 12:18:09 pm
I forgot: Another, more general way to prevent a form from closing is the OnCloseQuery event in which you simply set the parameter CanClose to false if the form should remain open. This technique is used primarily for the MainForm. In case of secondary forms it has problems, though, because the form even cannot be closed by the system close button ("x") which is generally very confusing to a user.
Title: Re: BitBtn bkClose closes window even though ModalResult is mrNone. Bug or feature?
Post by: Aidex on November 12, 2017, 12:26:39 pm
Yes, I see, but in my program the "Close" BitBtn is on a panel - to hide the panel - not to close a form.
So I want to prohibit the button to close a form in any case, because its function refers to a panel, not to a form.

Of course, I can use another button that won't close a form, but I think it's a bug that the bkClose BitBtn on Form1 always closes the program, altough it is to send mrNone as ModalResult.
Title: Re: BitBtn bkClose closes window even though ModalResult is mrNone. Bug or feature?
Post by: wp on November 12, 2017, 01:00:01 pm
I think it's a bug that the bkClose BitBtn on Form1 always closes the program, altough it is to send mrNone as ModalResult.
Certainly not. That's the way buttons are designed. A modal form executes a continuous loop which exits when its ModalResult is different from mrNone. The click on a button transfers its ModalResult to the Modalresult of the form, and therefore closes the form if the button's Modalresult is not mrNone. If the form is the MainForm then the program quits.

If you want the button to only hide a panel, then the button's ModalResult must be mrNone. But: in my tests it turned out that the form may close if the button's Kind is still mkClose; only after switching it back to mkCustom the form stayed open. (This step preserves the button's Close icon). Then, in the button's OnClick you can hide the panel.
Title: Re: BitBtn bkClose closes window even though ModalResult is mrNone. Bug or feature?
Post by: Aidex on November 12, 2017, 01:13:16 pm
Yes, that's all right and clear to me, but shouldn't the button behave on Form1 in the same way you're using it on Form2 ?!
So I'm still thinking that it's a bug to ignore its mrNone setting (property in IDE) of the bkClose button.
Should I report it as a bug?
Title: Re: BitBtn bkClose closes window even though ModalResult is mrNone. Bug or feature?
Post by: howardpc on November 12, 2017, 01:18:59 pm
No, the "Close" in TBitBtn's Kind property value bkClose  refers specifically to the closing of the button's containing form.
You cannot use a TBitBtn of Kind bkClose for closing panels etc. without working around the tightly integrated ModalResult and form-closing modality that is built in to TBitBtn in the LCL (if you don't want the button also to close the form). Far better to use a non-bkClose button for closing panels etc. when the 'problem' of the form's ModalResult changing behind your back is simply not present.

But a possible work-around would be as follows:

Code: Pascal  [Select]
  1. type
  2.  
  3.   TForm1 = class(TForm)
  4.     PanelCloseBitBtn: TBitBtn;
  5.     Panel1: TPanel;
  6.     procedure PanelCloseBitBtnMouseDown(Sender: TObject; Button: TMouseButton;
  7.       Shift: TShiftState; X, Y: Integer);
  8.     procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
  9.   private
  10.     PanelClosed: Boolean;
  11.   end;
  12.  
  13. var
  14.   Form1: TForm1;
  15.  
  16. implementation
  17.  
  18. procedure TForm1.PanelCloseBitBtnMouseDown(Sender: TObject; Button: TMouseButton;
  19.   Shift: TShiftState; X, Y: Integer);
  20. begin
  21.   if Sender is TBitBtn then begin
  22.     PanelCloseBitBtn.Enabled:=False;
  23.     PanelClosed:=True;
  24.     Panel1.Visible:=False;
  25.   end;
  26. end;
  27.  
  28. procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: boolean);
  29. begin
  30.   CanClose:=not PanelCloseBitBtn.Enabled or not PanelClosed;
  31.   PanelClosed:=False;
  32. end;
Title: Re: BitBtn bkClose closes window even though ModalResult is mrNone. Bug or feature?
Post by: ASerge on November 12, 2017, 01:43:44 pm
Hello!
I hoped mrNone would prevent automatically closing the form, but the window closes before I can handle the button's OnClick event.
As I understood mrNone, it shouldn't close a form.
Widely known, but not documented feature. When Kind = bkClose, always closed the parent form. If you like the "Close" picture, put the style in bkCustom, in this case the special behavior disappears, but the picture remains.
Title: Re: BitBtn bkClose closes window even though ModalResult is mrNone. Bug or feature?
Post by: FTurtle on November 12, 2017, 01:56:11 pm
Widely known, but not documented feature. When Kind = bkClose, always closed the parent form. If you like the "Close" picture, put the style in bkCustom, in this case the special behavior disappears, but the picture remains.

Code:
Code: Pascal  [Select]
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. begin
  3.   BitBtn1.Kind:=bkClose;
  4.   BitBtn1.Kind:=bkCustom;
  5.   BitBtn1.ModalResult:=mrNone;
  6. end;
  7.