Recent

Author Topic: How to really prevent a control from losing focus?  (Read 1992 times)

Sieben

  • Sr. Member
  • ****
  • Posts: 367
How to really prevent a control from losing focus?
« on: October 22, 2024, 09:03:15 pm »
Is there a way to really prevent a control from losing focus? The usual way - that's what I did in Delphi und what for example LCL's TMaskEdit does as well - is to sort of re-SetFocus in an inherited overridden DoExit. Problem is that while it looks as if the control keeps focus you can still click a button and that button's OnClick handler gets executed. In fact the control  first loses focus and only then sort of re-enters itself. I tried it all the way up from CMExit, LMKillFocus to WndProc to no avail. I'm trying to do it here on Linux/Gtk2 but it should work at least in Windows as well. Can't really remember right now if it was the same with Delphi but I suppose so.
« Last Edit: November 05, 2024, 05:11:06 pm by Sieben »
Lazarus 2.2.0, FPC 3.2.2, .deb install on Ubuntu Xenial 32 / Gtk2 / Unity7

rvk

  • Hero Member
  • *****
  • Posts: 6591
Re: How to really prevent a control from losing focus?
« Reply #1 on: October 22, 2024, 09:18:55 pm »
Problem is that while it looks as if the control keeps focus you can still click a button and that button's OnClick handler gets executed. In fact the control  first loses focus and only then sort of re-enters itself.
Are you sure? I put a TEdit on the form and a TButton. Assigned the events OnExit and OnClick.

When TEdit doesn't have focus, the showmessage below works.
When TEdit had focus, the TButton.OnClick isn't executed. The complete text does get 'selected' (as if you exited and entered again) but the showmessage doesn't show.

Is this different for you?
I'm on Windows. Is this different on Linux???

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   Showmessage('Click');
  4. end;
  5.  
  6. procedure TForm1.Edit1Exit(Sender: TObject);
  7. begin
  8.   Edit1.SetFocus;
  9. end;

Sieben

  • Sr. Member
  • ****
  • Posts: 367
Re: How to really prevent a control from losing focus?
« Reply #2 on: October 22, 2024, 09:40:32 pm »
Tried your very setup here on Linux/Gtk2 and yes, I see the message. And the edit doesn't do a SelectAll despite AutoSelect being True.
Lazarus 2.2.0, FPC 3.2.2, .deb install on Ubuntu Xenial 32 / Gtk2 / Unity7

rvk

  • Hero Member
  • *****
  • Posts: 6591
Re: How to really prevent a control from losing focus?
« Reply #3 on: October 22, 2024, 09:51:05 pm »
Then the order of things must be different in the Linux/Gtk2 widgetset.

Is TEdit.OnExit actually executed first, and is OnClick 'in the wait queue'?
Or is OnClick executed first.

You can see this if you put a Showmessage in the TEdit.OnExit.
If that shows first, maybe the queue (for the onclick) can be prevented.
If the OnClick executed first, then it's really different from Windows, and could even have serious sude-effects if you do some things in OnExit which you expect to happen before any other control gets focus. (Because this should also be the case for the OnEnters)

Maybe same issue as this
https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/31900
https://lazarus.lazarus.freepascal.narkive.com/CR6o3Sui/order-of-events-tedit-tlistbox
« Last Edit: October 22, 2024, 09:53:12 pm by rvk »

Sieben

  • Sr. Member
  • ****
  • Posts: 367
Re: How to really prevent a control from losing focus?
« Reply #4 on: October 22, 2024, 10:40:25 pm »
Now that's weird - as soon as I had the ShowMessage in the OnExit handler it works as expected and as you described - the other ShowMessage does not get executed and the edit does a SelectAll. Commented it out again and it was back to what I said in my previous post. Something seems to be rotten here...
Lazarus 2.2.0, FPC 3.2.2, .deb install on Ubuntu Xenial 32 / Gtk2 / Unity7

rvk

  • Hero Member
  • *****
  • Posts: 6591
Re: How to really prevent a control from losing focus?
« Reply #5 on: October 22, 2024, 10:43:56 pm »
The showmessage might mess up the flow here.

You can add a tmemo and add lines in onexit and onclick.
Then you should be able to see which is executed first.

If it's the onclick first, then this might be the same problem as in the past on gtk2/3.

Sieben

  • Sr. Member
  • ****
  • Posts: 367
Re: How to really prevent a control from losing focus?
« Reply #6 on: October 22, 2024, 11:02:44 pm »
I'm getting three Exits and then one Click... that very much resembles my experience when working on my component but decided to figure out that one later. Time for another Clean&Build, I guess.

Edit - Done, but same as before. When I bring the ShowMessages in again, I only get the EditExit, and only once. What's going on here? And yes, it may be related to that issue you mentioned.
« Last Edit: October 22, 2024, 11:18:50 pm by Sieben »
Lazarus 2.2.0, FPC 3.2.2, .deb install on Ubuntu Xenial 32 / Gtk2 / Unity7

jamie

  • Hero Member
  • *****
  • Posts: 6735
Re: How to really prevent a control from losing focus?
« Reply #7 on: October 23, 2024, 01:46:34 am »
I maybe wrong and it could be a widget limitation too however, in Windows I think I done this once, maybe it was Delphi?

In any case, if you place just an edit box within a borderless form, like maybe a TFRame and then have that frame shown as Modal.

Without the border icons and such I believe you don't get a shadow cast from the OS GUI.

 But that will prevent anything around you from receiving input.
The only true wisdom is knowing you know nothing

rvk

  • Hero Member
  • *****
  • Posts: 6591
Re: How to really prevent a control from losing focus?
« Reply #8 on: October 23, 2024, 10:02:11 am »
On Windows I get the Edit1.OnExit and a Edit1.OnEnter. Once.
No Button1.OnClick.

This could indeed be the widgetset but it shouldn't execute Button1.OnClick.
You could do things in Button1.OnClick expecting the Edit1.OnExit is correctly executed.

Funny part is that an Edit2.OnEnter (for another TEdit) isn't executed (but the first time the text in Edit2 is selected).

Yeah, definitely something weird.
You might want to report this (if this issue isn't already in the bugtracker).

BTW. The Button1.OnClick is actually executed after the OnExit. But the SetFocus should have prevented the execution.
You can set the Button1.Enabled to false and see it doesn't execute (and then the Edit1.OnExit is executed once ;) )

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Edit1Exit(Sender: TObject);
  2. begin
  3.   Memo1.Lines.Add('Edit1.OnExit');
  4.   Edit1.SetFocus;
  5.   Button1.Enabled := false;
  6. end;

Sieben

  • Sr. Member
  • ****
  • Posts: 367
Re: How to really prevent a control from losing focus?
« Reply #9 on: October 23, 2024, 12:52:52 pm »
Yes, there are ways to work around that and IMO you should always disable any buttons etc until an edit process is complete and meets your validations, a question not only of program flow but of user feedback as well.

I'm currently doing some more tests with other sort of controls, TMemo, TlistBox, whatever. There's not really a pattern yet, but TEdit seems to behave a bit different. Unfortunately the control I'm working on is a descendant of TCustomEdit as well, and I would very much like it to be 'self sufficient' without relying on environment conditions. But I'm rather glad to hear that it works on other platforms (which I currently cannot test myself, but will do so later). And as long as you can document anomalous behaviour you can't do anything about it should be, well, not fine, but sufficient.

As for filing a bug - will do when things become a bit clearer but I doubt there will be much work done anymore on fixing Gtk2 isues (if that's what it is). Btw there are other issues with the order of messages and events, as for example issue 20330 mentioned in TDBEdit concerning LMPaste, LMCut and LMClear. That one is still pending and has been for years.
Lazarus 2.2.0, FPC 3.2.2, .deb install on Ubuntu Xenial 32 / Gtk2 / Unity7

Sieben

  • Sr. Member
  • ****
  • Posts: 367
Re: How to really prevent a control from losing focus?
« Reply #10 on: November 03, 2024, 04:24:15 pm »
Had some other fish to fry but would like to come back here now. Preventing the OnExit handler to fire proved not only easy but was already implemented with my component - just don't call inherited DoExit until it validates ok and you can actually leave. The button click is another matter, however.

As for filing a bug report I need to know if this is confined to my somewhat peculiar Linux desktop here (Unity7) or if it is indeed a broader issue - Gtk2 or Linux altogether. So I would like to ask people on Linux platforms to run the little test project included here and do two little tests:

1) Run the program and tab out of Edit1 - Memo1 should display a singe 'Edit1Exit'. Now try to tab out of Edit2 (which is locked in it's OnExit handler) - how many 'Edit2Exit' are written to Memo1? Does Edit2 do a SelectAll when trying to tab out?

2) Run it once more, tab out of Edit1 into Edit2 and try to click Button1. Same questions as above plus is there any Button1Click written to Memo1?

And please don't forget to specify your platform (and your desktop if you happen to know).

Thanks a lot.
Lazarus 2.2.0, FPC 3.2.2, .deb install on Ubuntu Xenial 32 / Gtk2 / Unity7

rvk

  • Hero Member
  • *****
  • Posts: 6591
Re: How to really prevent a control from losing focus?
« Reply #11 on: November 05, 2024, 10:04:11 am »
a) how many 'Edit2Exit' are written to Memo1? 1x Edit2Exit (nothing else)
b) Does Edit2 do a SelectAll when trying to tab out? Yes


Windows 10 - Lazarus trunk - x86_64-win64-win32/win64
1) Tab out of Edit2
a) 1x Edit2Exit (nothing else)
b) Yes, autoselect

2) Click button
a) 1x Edit2Exit (nothing else)
b) Yes, autoselect

Ubuntu 22.04 - Gnome - Lazarus older trunk x86_64-linux-gtk2
1) Tab out of Edit2
a) 2x Edit2Exit (nothing else)
b) No - cursor @ start of line

2) Click button
a) 3x Edit2Exit + 1x Button1Click
b) No - cursor @ start of line

Kali 2024.1 - XFCE - Lazarus even older trunk x86_64-linux-qt5
1) Tab out of Edit2
a) 1x Edit2Exit (nothing else)
b) Yes, autoselect

2) Click button
a) 1x Edit2Exit + 1x Button1Click
b) Yes, autoselect

Sieben

  • Sr. Member
  • ****
  • Posts: 367
Re: How to really prevent a control from losing focus?
« Reply #12 on: November 05, 2024, 04:31:53 pm »
Thanks again, that's very interesting - and quite annoying. Looks like it's gonna be a complex bug report, but I'm unsure how to do it other than by pointing to this thread, especially given that I can't do these tests myself and would have to rely on hearsay, no matter how much I trust it. On the other hand I would consider this a serious matter on both Gtk2 and Qt5, since that ButtonClick should not be possible at all. Looks like Windows is the only reliable platform here - and I always thought focus issues were a mess there.
« Last Edit: November 05, 2024, 05:09:57 pm by Sieben »
Lazarus 2.2.0, FPC 3.2.2, .deb install on Ubuntu Xenial 32 / Gtk2 / Unity7

rvk

  • Hero Member
  • *****
  • Posts: 6591
Re: How to really prevent a control from losing focus?
« Reply #13 on: November 05, 2024, 05:03:52 pm »
On the other hand I would considers this a serious matter on both Gtk2 and Qt5, since that ButtonClick should not be possible at all. Looks like Windows is the only reliable platform here - and I always thought focus issues were a mess there.
Yes. qt5/Linux almost worked but the fact that the Button1Click 'bleeds' through when focus is prevented is indeed a serious issue.

I haven't had the chance yet to test qt5 on Windows.

Sieben

  • Sr. Member
  • ****
  • Posts: 367
Re: How to really prevent a control from losing focus?
« Reply #14 on: November 11, 2024, 02:01:14 pm »
Just a few remarks on possible workarounds (and to keep this topic floating): you can reliably prevent the Button1Click handler to be executed by placing this right at the top of it's code:

Code: Pascal  [Select][+][-]
  1.   {$ifdef LCLGtk2}
  2.   if not Button1.Focused then Exit;
  3.   {$endif}  
  4.  

and you can make the SelectAll of Edit2 (all this refers to the test project included above) work by inserting this between SetFocus and SelectAll:

Code: Pascal  [Select][+][-]
  1.   Edit2.SetFocus;
  2.   {$ifdef LCLGtk2}
  3.   Application.ProcessMessages;
  4.   {$endif}
  5.   Edit2.SelectAll;  
  6.  

I did not test with Qt5 so far.
« Last Edit: November 11, 2024, 02:04:19 pm by Sieben »
Lazarus 2.2.0, FPC 3.2.2, .deb install on Ubuntu Xenial 32 / Gtk2 / Unity7

 

TinyPortal © 2005-2018