Developers often get requests to create forms where it is crucial to pay attention to the position of a cursor after the Tab key is pressed at every point of the program execution. This can be particularly important when developing cross platform apps where following user’s expectations of how user interfaces should behave can help make your app seem professional. It can be important from different perspectives, including user experience, client’s requirements, and important things like functionality. Delphi provides wide opportunities for this thanks to the implementation of the “TabOrder” property.
In this article, we offer you to take a closer look at the TabOrder property in Delphi, to analyze how it’s supported, how it can be used and to see whether there are any limitations.
What is a taborder and what does it do?
The TabOrder property has been a part of Delphi since the release of Delphi 1. In earlier versions of Delphi, TabOrder was a part of the VCL hierarchy while in newer versions it is a part of FMX with small changes in the hierarchy.
When the Tab key is pressed, the focus moves from one control to the next one. Due to the peculiarities of their design, not all controls can receive focus (E.g. TLabel) and not all controls can participate in the tab navigation. Even controls that can receive focus must be explicitly included in the tab sequence.
In VCL, TabOrder is defined in the TWinControl class that normally unites components that are derived ultimately from the TWinControl class and will have the TabOrder property.
Below you can see a typical declaration of the TabOrder property in the TWinControl class.
property TabOrder: TTabOrder read GetTabOrder write SetTabOrder;
TTabOrder is defined as an Enumeration that can contain values from -1 to 32767.
Controls with a TabOrder value that equals -1 will be skipped during the Tab Ordering when the tab key is pressed.
How is taborder different in a cross-platform app?
In FMX, TabOrder is a part of the TControl class and is declared similar to the TWinControl class in VCL as described above.
There is one more property named TabStop which determines whether a control will receive focus or not depending on the TabStop property value. Controls with a TabStop value that is False will not receive focus regardless of their TabOrder value. This principle is similar to the cases when the TabOrder value equals -1.
As per the Embarcadero documentation, the TabOrder property is indicated as the position of the control in its parent’s tab order.
This means that each parent control will have its own list of Tab Orders. An ultimate parent form that has all controls sitting over it also contains a list of tab orders for all controls (except the ones which are children of other controls on the same form).
The control on the parent form which has a TabOrder set to 0 will have focus when the form first appears.
Initially, when you create components at the design time, the tab order is always the order in which controls were added to the form. The first control added to the form has a TabOrder value of 0, the second one’s value equals 1, the third one has a value of 2, and so on. As we have seen above in the declaration for the TabOrder property, TabOrder is a writable property. So, you can always set a TabOrder value as per your requirements. Since TabOrder is an Integer enumeration, its value should always be somewhere in the range from -1 to 32767.
How to set the taborder for a control in cross platform apps
Each control has a unique TabOrder value within its parent. If you change the TabOrder property value of one of its controls to the same value as another control has, the TabOrder value for all other controls on the same parent form changes accordingly. For example, let’s suppose that a control is the sixth in its tab order. If you change the control’s TabOrder property value to 3 (making the control fourth in the tab order), the control that was originally the fourth in the tab order now becomes the fifth, and the control that was the fifth becomes the sixth.
Assigning a TabOrder value that will be higher than the number of controls contained in the parent control essentially moves the control to the end of the tab order. The control does not take on the assigned value of TabOrder, but instead, it gets the number that will show that the control is the last in the tab order.
To demonstrate the use of TabOrder in FMX, we’ve created an application in Delphi 10.4. It’s not a very good-looking one but you can see it below.
In the screenshot placed above, you can see the creation of a form with multiple controls on it.
Generally, when we create forms like this we need to ensure the right tab order from the perspective of the user experience.
Creating controls based on Tab Orders requirement
One possible way to do that is to take care of that while creating controls during the design time. In this approach, we need to create controls in such a way that their tab orders will be correct in accordance with the requirement. But it’s not always possible to follow this approach as user interfaces change a lot due to updates that can be introduced to the requirements.
Use of object Inspector to update Tab Orders
Another way to set the correct tab order is to edit a tab order for each control in the object inspector individually and to set the TabOrder property to the one we need.
In the screenshot below, you can see how we have set all TabOrder properties of controls in accordance with our requirements.
Here, the first component has the TabOrder set to 0.
The panel where buttons A, B, C and D are located has the TabOrder set to 1. It is shown on the screenshot below.
As we’ve already explained, each parent control has its own list of tab orders. This is demonstrated in the following screenshot.
Button A has the TabOrder 0 as it is a child component of the Panel but not the form. The tab orders of other buttons are demonstrated below.
So, setting TabOrder properties manually from the object inspector for all controls on the form is one of the ways to ensure the correct flow of focus in the application. But this becomes quite tiresome with the introduction of more and more additional controls on a form.
How to use the Tab Orders dialog box to set tab orders in native and cross platform apps
Embarcadero seems to be well aware of all the complications that we as developers go through while setting up tab orders of controls on a Delphi form.
So, to simplify this task the company provides an option in the IDE to set tab orders of all controls on a parent control in one go. Make a Right Click on your parent component and select the option: “Tab Order…”
After clicking on it you will see a dialog box where all child controls of that parent component are listed ordered by their TabOrders.
You can go ahead and move controls up and down as per requirements to set your Tab Order sequence.
The Tab Order dialog feature is very useful in the case of forms with multiple Tabs, panels and numerous components. This will generally help us to achieve almost all requirements that we get in terms of Tab Orders.
Using the third-party CnWizards IDE add-in components to set taborders for native and cross platform apps
Developers are not supposed to restrict their solutions by the functionalities that IDEs offer. Otherwise, they are free to explore, create and extend those functionalities to make their lives easier.
The CnPack community has followed this principle and created components that are useful for the Delphi Developers community and are open source.
One of the components which is of great use is CnWizards. We will not go through the entire functionality that it provides today. Let’s have a look at the one that is relevant in our case, and it is Tab Orders wizard.
Tab Orders wizard is a CnWizards component that provides functionalities necessary to quickly set, modify (automatically and manually & horizontally and vertically), show Tab Orders of components, and to fulfill many other tasks.