Capturing the tab order of a focused item lazarus / 31-LCL ---------------------------------------------------------------------- MaxCuriosus · 2020-04-25 11:57 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 · 2020-04-25 12:33 I don't know exactly what you want to do but you can get the currently focused control with something like: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function GetFocusedControl(const Root: TControl): TControl;var  i: Integer;begin  Result := Nil  if Root.ControlCount > 0 then begin    for i := 0 to Root.ControlCount-1 do      if (Root.Controls[i] is TWinControl)      and TWinControl(Root.Controls[i].Focused) then begin        Result := Root.Controls[i];        Break;      end else      if Root.Control[i].ControlCount > 0 then begin          Result := GetFocusedControl(Root.Control[i]);          if Assigned(Result) then Break;        end;  end;end; And to get the tab order: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i AControl := GetFocusedControl(MyForm);if Assigned(AControl) and (AControl is TWinControl) then  Order := TWincontrol(AControl).TabOrder;  {Or whatever you want} ---------------------------------------------------------------------- howardpc · 2020-04-25 13:08 Perhaps something like this? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit uMain; {$mode objfpc}{$H+} interface uses  SysUtils, Forms, Controls, StdCtrls; type  TForm1 = class(TForm)  published    procedure FormCreate(Sender: TObject);    procedure IdleEvent(Sender: TObject; var Done: Boolean);  private const    ButtonCount: Integer = 5;  private    FButtons: array of TButton;  end; var  Form1: TForm1; implementation {$R *.lfm} procedure TForm1.FormCreate(Sender: TObject);var  i: Integer;begin  SetLength(FButtons, ButtonCount);  for i := 0 to High(FButtons) do    begin      FButtons[i] := TButton.Create(Self);      FButtons[i].Caption := Format('Button%d',[i+1]);      FButtons[i].Name := FButtons[i].Caption;      FButtons[i].Left := 20;      FButtons[i].Top := i*30 + 20;      FButtons[i].Parent := Self;    end;  Application.OnIdle := @IdleEvent;end; procedure TForm1.IdleEvent(Sender: TObject; var Done: Boolean);const  priorActiveControl: TWinControl = Nil;begin  case Assigned(ActiveControl) of    True:  begin             if (ActiveControl <> priorActiveControl) and (ActiveControl is TButton) then               begin                 Caption := Format('%s is active (taborder %d)',[ActiveControl.Name, ActiveControl.TabOrder]);               priorActiveControl := ActiveControl;               end;           end;    False: Caption := 'There is no control active at present';  end;  Done := True;end; end. ---------------------------------------------------------------------- MaxCuriosus · 2020-04-26 10:05 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 · 2020-04-26 13:52 Quote from: MaxCuriosus on April 26, 2020, 12:05:46 pmwith 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function GetFocusedControl(const Root: TWinControl): TControl;var  i: Integer;  Ctrl: TControlbegin  Result := Nil  if Assigned(Root) and (Root.ControlCount > 0) then begin    for i := 0 to Root.ControlCount-1 do begin      Ctrl := Root.Controls[i];      if Ctrl is TWinControl then begin        if TWinControl(Ctrl).Focused then          Result := Ctrl;        else          if TWinControl(Ctrl).ControlCount > 0 then            Result := GetFocusedControl(Ctrl);        if Assigned(Result) then Break;      end;    end;  end;end; And: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i AControl := GetFocusedControl(MyForm);if Assigned(AControl) and (AControl is TWinControl) then  Order := TWincontrol(AControl).TabOrderelse  Order := -1;  {Or whatever you want} ---------------------------------------------------------------------- jamie · 2020-04-26 18:51 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.. ---------------------------------------------------------------------- MaxCuriosus · 2020-04-26 19:49 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 · 2020-04-26 20:04 Quote from: MaxCuriosus on April 26, 2020, 09:49:25 pmlucamar, 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i          if TWinControl(Ctrl).ControlCount > 0 then            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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function GetFocusedControl(const Root: TWinControl): TWinControl;var  i: Integer;  Ctrl: TWinControl;begin  Result := Nil;  if Assigned(Root) and (Root.ControlCount > 0) then begin    for i := 0 to Root.ControlCount-1 do begin      if Root.Controls[i].InheritsFrom(TWinControl) then        Ctrl := Root.Controls[i] as TWinControl;      if Ctrl.Focused then        Result := Ctrl      else        if Ctrl.ControlCount > 0 then        Result := GetFocusedControl(Ctrl);      if Assigned(Result) then Break;    end;  end;end; procedure TForm1.Button1Click(Sender: TObject);var  AControl: TWinControl;begin  AControl := GetFocusedControl(Self);  if Assigned(AControl) then    ShowMessageFmt('Focusesed control %s (a %s) has TabOrder: %d',                 [AControl.Name, AControl.ClassName, AControl.TabOrder])  else    ShowMessage('No control seems to be focused!?');end; ---------------------------------------------------------------------- MaxCuriosus · 2020-04-26 20:14 lucamar, OK now that the compiling is successful, I will check how the recursivity work. Thank you. ---------------------------------------------------------------------- lucamar · 2020-04-26 20:31 Quote from: MaxCuriosus on April 26, 2020, 10:14:44 pmI 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. ---------------------------------------------------------------------- MaxCuriosus · 2020-04-26 20:34 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {...} procedure TForm1.IdleEvent(Sender: TObject; var Done: Boolean);const  priorActiveControl: TWinControl = Nil;begin  case Assigned(ActiveControl) of    True:  begin             if (ActiveControl <> priorActiveControl) and (ActiveControl is TButton) then               begin//                 Caption := Format('%s is active (taborder %d)',[ActiveControl.Name, ActiveControl.TabOrder]);               if PriorActiveControl<>Nil then                   priorActiveControl.Font.Color := clDefault;                 priorActiveControl := ActiveControl;                 ActiveControl.Font.Color:=clRed; // and also bold face by default                     end;           end; //   False: Caption := 'There is no control active at present';  end;  Done := True;end; ---------------------------------------------------------------------- jamie · 2020-04-26 22:28 Let me add to the list here Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);var  A:TFPlist;begin  A := TFPList.Create;  Form1.GetTabOrderList(A);  Caption := A.IndexOf(Pointer(ActiveControl)).ToString;  A.Free;end; ---------------------------------------------------------------------- jamie · 2020-04-26 22:42 and this one Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);begin  caption := Form1.GetControlIndex(ActiveControl).ToString;end;                                                     you see, etherway you can get TabOrder index or Control index... ---------------------------------------------------------------------- howardpc · 2020-04-27 09:46 Quote from: MaxCuriosus on April 26, 2020, 10:34:30 pmhowardpc, 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 · 2020-04-27 21:56 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. ---------------------------------------------------------------------- eljo · 2020-04-27 23:16 Sorry if this has already been said but I see a lot redundant code flying around and I have no desire to read it all, so I'll just ask have you tried Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   showmessage(inttotsr(Form1.ActiveControl.TabOrder)); and if yes what is the problem you stumble upon exactly. ---------------------------------------------------------------------- jamie · 2020-04-28 00:14 I think tab order was a mistake when asked, what they really wanted was the index of where it lived in the order of controls.  The TABORDER may not always be the same order of the control in the controls array.. So if a person needs to know which control is the next or before in the order of creation that could use many of the already existing methods...  I believe this person is writing a RAD system by looking at his post. ---------------------------------------------------------------------- MaxCuriosus · 2020-04-28 22:47 eljo, what I wanted to achieve has been achieved, see reply #10. Everything else is for my learning experience. Thank you for your suggestion anyway.