Recent

Author Topic: Capturing the tab order of a focused item  (Read 3045 times)

MaxCuriosus

  • Full Member
  • ***
  • Posts: 145
Capturing the tab order of a focused item
« on: April 25, 2020, 01:57:35 pm »
In a form that has a few buttons I would like to determine which one has the actual focus based on the tab order/index of that button. Is there some kind of form property that can be used for that?

lucamar

  • Hero Member
  • *****
  • Posts: 4217
Re: Capturing the tab order of a focused item
« Reply #1 on: April 25, 2020, 02:33:58 pm »
I don't know exactly what you want to do but you can get the currently focused control with something like:

Code: Pascal  [Select][+][-]
  1. function GetFocusedControl(const Root: TControl): TControl;
  2. var
  3.   i: Integer;
  4. begin
  5.   Result := Nil
  6.   if Root.ControlCount > 0 then begin
  7.     for i := 0 to Root.ControlCount-1 do
  8.       if (Root.Controls[i] is TWinControl)
  9.       and TWinControl(Root.Controls[i].Focused) then begin
  10.         Result := Root.Controls[i];
  11.         Break;
  12.       end else
  13.         if Root.Control[i].ControlCount > 0 then begin
  14.           Result := GetFocusedControl(Root.Control[i]);
  15.           if Assigned(Result) then Break;
  16.         end;
  17.   end;
  18. end;

And to get the tab order:

Code: Pascal  [Select][+][-]
  1. AControl := GetFocusedControl(MyForm);
  2. if Assigned(AControl) and (AControl is TWinControl) then
  3.   Order := TWincontrol(AControl).TabOrder;
  4.   {Or whatever you want}


Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Capturing the tab order of a focused item
« Reply #2 on: April 25, 2020, 03:08:18 pm »
Perhaps something like this?
Code: Pascal  [Select][+][-]
  1. unit uMain;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   SysUtils, Forms, Controls, StdCtrls;
  9.  
  10. type
  11.   TForm1 = class(TForm)
  12.   published
  13.     procedure FormCreate(Sender: TObject);
  14.     procedure IdleEvent(Sender: TObject; var Done: Boolean);
  15.   private const
  16.     ButtonCount: Integer = 5;
  17.   private
  18.     FButtons: array of TButton;
  19.   end;
  20.  
  21. var
  22.   Form1: TForm1;
  23.  
  24. implementation
  25.  
  26. {$R *.lfm}
  27.  
  28. procedure TForm1.FormCreate(Sender: TObject);
  29. var
  30.   i: Integer;
  31. begin
  32.   SetLength(FButtons, ButtonCount);
  33.   for i := 0 to High(FButtons) do
  34.     begin
  35.       FButtons[i] := TButton.Create(Self);
  36.       FButtons[i].Caption := Format('Button%d',[i+1]);
  37.       FButtons[i].Name := FButtons[i].Caption;
  38.       FButtons[i].Left := 20;
  39.       FButtons[i].Top := i*30 + 20;
  40.       FButtons[i].Parent := Self;
  41.     end;
  42.   Application.OnIdle := @IdleEvent;
  43. end;
  44.  
  45. procedure TForm1.IdleEvent(Sender: TObject; var Done: Boolean);
  46. const
  47.   priorActiveControl: TWinControl = Nil;
  48. begin
  49.   case Assigned(ActiveControl) of
  50.     True:  begin
  51.              if (ActiveControl <> priorActiveControl) and (ActiveControl is TButton) then
  52.                begin
  53.                  Caption := Format('%s is active (taborder %d)',[ActiveControl.Name, ActiveControl.TabOrder]);
  54.                  priorActiveControl := ActiveControl;
  55.                end;
  56.            end;
  57.     False: Caption := 'There is no control active at present';
  58.   end;
  59.   Done := True;
  60. end;
  61.  
  62. end.

MaxCuriosus

  • Full Member
  • ***
  • Posts: 145
Re: Capturing the tab order of a focused item
« Reply #3 on: April 26, 2020, 12:05:46 pm »
lucamar,
with your code the compiler complains a lot with

Error: identifier idents no member "ControlCount"
Error: identifier idents no member "Controls"

In the unit "Controls" under "TControl" I could not find those identifiers. Is there a minimum version for Lazarus/Pascal? My configuration is Deb9/Laz2.0.2/FPC3.0.4/x86_64-linux-gtk2.

lucamar

  • Hero Member
  • *****
  • Posts: 4217
Re: Capturing the tab order of a focused item
« Reply #4 on: April 26, 2020, 03:52:13 pm »
with your code the compiler complains a lot with
Error: identifier idents no member "ControlCount"
Error: identifier idents no member "Controls"

Yeah, sorry :-[
Actually, those (as well as TabOrder and Focused) are properties of TWinControl, not of TControl; it should have been:

Code: Pascal  [Select][+][-]
  1. function GetFocusedControl(const Root: TWinControl): TControl;
  2. var
  3.   i: Integer;
  4.   Ctrl: TControl
  5. begin
  6.   Result := Nil
  7.   if Assigned(Root) and (Root.ControlCount > 0) then begin
  8.     for i := 0 to Root.ControlCount-1 do begin
  9.       Ctrl := Root.Controls[i];
  10.       if Ctrl is TWinControl then begin
  11.         if TWinControl(Ctrl).Focused then
  12.           Result := Ctrl;
  13.         else
  14.           if TWinControl(Ctrl).ControlCount > 0 then
  15.             Result := GetFocusedControl(Ctrl);
  16.         if Assigned(Result) then Break;
  17.       end;
  18.     end;
  19.   end;
  20. end;

And:

Code: Pascal  [Select][+][-]
  1. AControl := GetFocusedControl(MyForm);
  2. if Assigned(AControl) and (AControl is TWinControl) then
  3.   Order := TWincontrol(AControl).TabOrder
  4. else
  5.   Order := -1;
  6.   {Or whatever you want}
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

jamie

  • Hero Member
  • *****
  • Posts: 7768
Re: Capturing the tab order of a focused item
« Reply #5 on: April 26, 2020, 08:51:58 pm »
Something tells me the order In which the one before and one next is needed..

How about using the  FORM1.GetTabOrderList(AList) ?

 and from that, you could I guess determine who is who..

The only true wisdom is knowing you know nothing

MaxCuriosus

  • Full Member
  • ***
  • Posts: 145
Re: Capturing the tab order of a focused item
« Reply #6 on: April 26, 2020, 09:49:25 pm »
lucamar,
with your latest code the compiler complains at line 15:

Error: Incompatible type for arg no. 1: Got "TControl", expected "TWinControl"

I think there is an inherent incompatibilty due to the recursive nature of your algorithm. That may be not trivial to resolve. Could you try to compile it on your system?

lucamar

  • Hero Member
  • *****
  • Posts: 4217
Re: Capturing the tab order of a focused item
« Reply #7 on: April 26, 2020, 10:04:29 pm »
lucamar,
with your latest code the compiler complains at line 15:

Error: Incompatible type for arg no. 1: Got "TControl", expected "TWinControl"

I think there is an inherent incompatibilty due to the recursive nature of your algorithm. That may be not trivial to resolve. Could you try to compile it on your system?

No incompatibility, just plain human error: I changed the function to accept a TWinControl so, of course, one can't pass a TControl to it  :-[

Just change those lines to:
Code: Pascal  [Select][+][-]
  1.          if TWinControl(Ctrl).ControlCount > 0 then
  2.             Result := GetFocusedControl(Ctrl as TWinControl);

By now that code has had so many iterations that it's become plain ugly, what with all those type-casts. if I were to use it I would expend a couple minutes making a new, more elegant function.


Edited to add:

Ok, new, tested code:

Code: Pascal  [Select][+][-]
  1. function GetFocusedControl(const Root: TWinControl): TWinControl;
  2. var
  3.   i: Integer;
  4.   Ctrl: TWinControl;
  5. begin
  6.   Result := Nil;
  7.   if Assigned(Root) and (Root.ControlCount > 0) then begin
  8.     for i := 0 to Root.ControlCount-1 do begin
  9.       if Root.Controls[i].InheritsFrom(TWinControl) then
  10.         Ctrl := Root.Controls[i] as TWinControl;
  11.       if Ctrl.Focused then
  12.         Result := Ctrl
  13.       else
  14.         if Ctrl.ControlCount > 0 then
  15.           Result := GetFocusedControl(Ctrl);
  16.       if Assigned(Result) then Break;
  17.     end;
  18.   end;
  19. end;
  20.  
  21. procedure TForm1.Button1Click(Sender: TObject);
  22. var
  23.   AControl: TWinControl;
  24. begin
  25.   AControl := GetFocusedControl(Self);
  26.   if Assigned(AControl) then
  27.     ShowMessageFmt('Focusesed control %s (a %s) has TabOrder: %d',
  28.                    [AControl.Name, AControl.ClassName, AControl.TabOrder])
  29.   else
  30.     ShowMessage('No control seems to be focused!?');
  31. end;
« Last Edit: April 26, 2020, 10:26:36 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

MaxCuriosus

  • Full Member
  • ***
  • Posts: 145
Re: Capturing the tab order of a focused item
« Reply #8 on: April 26, 2020, 10:14:44 pm »
lucamar,
OK now that the compiling is successful, I will check how the recursivity work. Thank you.

lucamar

  • Hero Member
  • *****
  • Posts: 4217
Re: Capturing the tab order of a focused item
« Reply #9 on: April 26, 2020, 10:31:19 pm »
I will check how the recursivity work. Thank you.

It's actually easy: You first pass a TWinControl to check its Controls and if it returns a focused one that's that; otherwise, we see if it's some kind of container and, if so, re-call the function to to check its controls and if it returns a focused one ...

You get the drift I guess; It basically resembles what we'd do (more or less) to find a node in a tree.
« Last Edit: April 26, 2020, 10:33:51 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

MaxCuriosus

  • Full Member
  • ***
  • Posts: 145
Re: Capturing the tab order of a focused item
« Reply #10 on: April 26, 2020, 10:34:30 pm »
howardpc,
thank you for your suggestion. I've adapted your code as below, which allows me to make the focused button more immediately visible. However the button font color changes under Linux but not under Windows. Any idea why?

Code: Pascal  [Select][+][-]
  1. {...}
  2.  
  3. procedure TForm1.IdleEvent(Sender: TObject; var Done: Boolean);
  4. const
  5.   priorActiveControl: TWinControl = Nil;
  6. begin
  7.   case Assigned(ActiveControl) of
  8.     True:  begin
  9.              if (ActiveControl <> priorActiveControl) and (ActiveControl is TButton) then
  10.                begin
  11. //                 Caption := Format('%s is active (taborder %d)',[ActiveControl.Name, ActiveControl.TabOrder]);
  12.                  if PriorActiveControl<>Nil then
  13.                    priorActiveControl.Font.Color := clDefault;
  14.                  priorActiveControl := ActiveControl;
  15.                  ActiveControl.Font.Color:=clRed; // and also bold face by default        
  16.                end;
  17.            end;
  18.  //   False: Caption := 'There is no control active at present';
  19.   end;
  20.   Done := True;
  21. end;

jamie

  • Hero Member
  • *****
  • Posts: 7768
Re: Capturing the tab order of a focused item
« Reply #11 on: April 27, 2020, 12:28:29 am »
Let me add to the list here ;)

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   A:TFPlist;
  4. begin
  5.   A := TFPList.Create;
  6.   Form1.GetTabOrderList(A);
  7.   Caption := A.IndexOf(Pointer(ActiveControl)).ToString;
  8.   A.Free;
  9. end;                          
  10.  

 :o
The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 7768
Re: Capturing the tab order of a focused item
« Reply #12 on: April 27, 2020, 12:42:27 am »
and this one
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   caption := Form1.GetControlIndex(ActiveControl).ToString;
  4. end;                                                      
  5.  

you see, etherway you can get TabOrder index or Control index...
The only true wisdom is knowing you know nothing

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Capturing the tab order of a focused item
« Reply #13 on: April 27, 2020, 11:46:15 am »
howardpc,
thank you for your suggestion. I've adapted your code as below, which allows me to make the focused button more immediately visible. However the button font color changes under Linux but not under Windows. Any idea why?
I don't use Windows unless forced to, so I do not know.
However, my guess would be that a difference might arise because of differences between the OS messaging systems.
If so, an

    Application.ProcessMessages
call might make a difference?

MaxCuriosus

  • Full Member
  • ***
  • Posts: 145
Re: Capturing the tab order of a focused item
« Reply #14 on: April 27, 2020, 11:56:50 pm »
Well gentlemen, there is a lot of new stuff (for me) to digest. If I don't get an indigestion I will keep you posted.
Thank you all.

 

TinyPortal © 2005-2018