2

I created a test new FMX project. Added a TabControl to it. Used the context menu to add 3 tabsheets. To the 3rd tabsheet, added a TEdit. Added a OnChangeEvent handler to the tabcontrol. Coded it as follows:

procedure TForm1.TabControl1Change(Sender: TObject);
begin
  if TabControl1.ActiveTab = TabItem3 then
  begin
    self.ActiveControl := Edit1;
    self.Focused := Edit1;
    Edit1.SetFocus;
  end;
end;

As you can see, I tried various combinations based on my previous VCL experience. The input/cursor focus does not change to the Edit1 by code. Of course, at runtime on Win32, if I click on the edit1, the focus rectangle (I'm using a style) now shows as does the cursor. (as expected) On Android. The VK only comes up when I shift the focus myself.

Is there way to do this programmatically so the user can just start typing? (without having to shift the focus to the TEdit themselves).

Freddie Bell
  • 2,186
  • 24
  • 43
  • You probably cannot change focus in this `OnTabControl1Change` event. Set a flag and check this flag in a timer or send a delayed message to your form. – LU RD Apr 19 '16 at 09:36
  • Interesting answer! I put an OnCanFocus event handler on the TEdit and it was called. It's just that the cursor (and VK) don't show. If I'm going to use a timer, I might as well use an anonymous thread... – Freddie Bell Apr 19 '16 at 09:45
  • Yes, I was just writing an anonymous thread for you! Well, since you got it, please answer your question for future readers to see. – LU RD Apr 19 '16 at 09:47

2 Answers2

9

The firemonkey framework prohibits change of focus in some events.

In order to change the focus, send a delayed message to the form.

This could be done with an anonymous thread:

procedure TForm1.TabControl1Change(Sender: TObject);
begin
  if TabControl1.ActiveTab = TabItem3 then
  begin
    TThread.CreateAnonymousThread(
      procedure
      begin
        TThread.Synchronize( nil,
          procedure
          begin
            Edit1.SetFocus;
          end
        );
      end
    ).Start;
  end;
end;

To make it more general, use a dedicated procedure:

procedure DelayedSetFocus(control : TControl);
begin
  TThread.CreateAnonymousThread(
    procedure
    begin
      TThread.Synchronize( nil,
         procedure
         begin
           control.SetFocus;
         end
      );
    end
  ).Start;
end;
Daniel Grillo
  • 2,368
  • 4
  • 37
  • 62
LU RD
  • 34,438
  • 5
  • 88
  • 296
0

In XE6 the suggested code only worked when I added a begin after the second line procedure:

procedure DelayedSetFocus(control : TControl);
begin
  TThread.CreateAnonymousThread(
    procedure
    begin
      TThread.Synchronize( nil,
         procedure
         begin
           control.SetFocus;
         end
      );
    end
  ).Start;
end;
Joost
  • 1
  • 2