Previously in Delphi VCL applications it was easy to "over ride" the key strokes on either the onkeyup or onkeydown events of components to make the Enter key behave as a TAB key. FireMonkey applications work differently from VCL, so how should one do this now?
2 Answers
I'm editing my answer to provide another solution thanks to the simple solution provided by @Uwe Raabe. I'm leaving everything here as this answer exposes some of the "magic" in Firemonkey which often isn't obvious.
I needed to create the "TAB" functionality dynamically on FormShow event of a Form to save myself time on implementation. I needed to make a class to handle the TNotifyEvent (OnClick). Here is my other solution which I have tested now with success. Please note the code below will attempt to remove "Default" button action on Enter so it works.
type TClickObject = class(TObject) public Form: TForm; procedure MyTabOnClick(Sender: TObject); end; { ClickClass } procedure TClickObject.MyTabOnClick(Sender: TObject); var ch: Char; key: Word; begin if Form = nil then Exit; key := vkTab; ch := #9; Form.KeyDown(key, ch, []); end; function CreateTabButton(Form: TForm): TButton; var Count: Integer; ClickObject: TClickObject; begin //Make the click object ClickObject := TClickObject.Create; ClickObject.Form := Form; //Make other buttons not default for Count := 0 to Form.ComponentCount-1 do begin if (Form.Components[Count] is TButton) then //Extend for other buttons ? begin (Form.Components[Count] as TButton).Default := False; end; end; //Make a button far off the screen Result := TButton.Create(Form); Result.Parent := Form; Result.Default := True; Result.OnClick := ClickObject.MyTabOnClick; Result.Text := 'TAB'; Result.Position.X := -10000; Result.Position.Y := -10000; end; //Form OnShow Event, declare tabButton as TButton in your Form then you can use it on other components like combo boxes where you want to fire tab / enter event tabButton := CreateTabButton(Self); The TComboBox for example does does not place nice with the Button solution, here is an example of making it work
procedure TForm1.CommboBox1KeyUp(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState); begin if (Key = 13) then begin tabButton.OnClick(self); //tabButton declared in the Form an initialized with CreateTabButton end; end; The following code is a procedure which can be used from a global library or TDataModule to provide you with the Enter to Tab functionality. I used the onkeyup events on inputs to test it.
procedure HandleEnterAsTab(Form: TForm; Sender: TObject; Key: Word); var TabList: ITabList; CurrentControl, NextControl: IControl; begin if (Key = vkReturn) then begin TabList := Form.GetTabList; CurrentControl := TControl(Sender); NextControl := TabList.FindNextTabStop(CurrentControl, True, False); if (NextControl = nil) then //go to first item if reached end begin NextControl := TabList.GetItem(0); end; NextControl.SetFocus; end; end; The following is an example snippet of it's use
procedure TForm1.Edit2KeyUp(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState); begin HandleEnterAsTab(Form1, Sender, Key); end; Obviously you could change the procedure to work differently according to your needs however I have tried to make it as generic as possible by using TComponent and TForm as the container for getting the TabList.
5 Comments
AdvanceTabFocus that is part of TCommonCustomForm class would not be declared as private but instead as public. This is the method that is executed when you change the focus using TAB key. But hey why would be this method public? Why would anybody need it? So now those that would need it are forced of reinventing the wheel and doing silly workarounds. I must say that I'm getting more and more disappointed with Embarcadero code lately.As I already mentioned in a comment, another way is to drop a TButton on the form, set TabStop = False and Default = True. The make it small and hide it under another control.
In the OnClick event of the button execute the following code:
var ch: Char; key: Word; begin key := vkTab; ch := #9; KeyDown(key, ch, []); end; Note that any other button having focus takes precedence over this, so the expected behavior is preserved.