Struggling with setting the right focus tab order
-
Hi all,
I am using Qt 5.12.8 and I am struggling with having the correct focus chain in an application where custom widgets could be dynamically inserted. In the picture below, 'A' was first inserted, then 'B', then 'C' and finally 'D'. I used QBoxLayout::insertWidget to be able to insert these widgets in a random order in the parent widget layout.
'D' was inserted between 'A' and 'B', so I would expect that it would be likewise be inserted in the focus chain, but it is appended after the last previously inserted widget 'C'. Moreover, if I iterate over QBoxLayout::children() or QBoxLayout::findChildren(), just as with the focus chain, the widgets are ordered according to when they are inserted instead of where.
I found a solution by updating a parallel list of widgets each time one is inserted, and as this list has the expected order, I can use it to fix the focus chain with QWidget::setTabOrder. However, I couldn't manage to make this solution work when the widgets are hierarchically ordered as on the picture below:
Indeed, I have the issue that when I don't provide the Qt::FindDirectChildrenOnly option to QBoxLayout::findChildren, it returns 7 times more objects as they really are. In the first example, if I call findChildren<Block_Widget*>(), where Block_Widget is the type of the custom widget, this method returns me 28 elements instead of 4. Is it a bug?
Moreover, in the 2nd example, if I insert at a specific place a widget containing a hierarchy of other widgets, I need to access the highest and the lowest sub-widgets of this widget in order to fix the focus chain. For example the widget hierarchy beginning with widget "What is a design proposal" has this widget as highest sub-widget and the paragraph beginning by "First you need..." as its lowest sub-widget.
Is there an easier way to fix this issue? Like is it possible to reorder the children from the layout according to there location?
Thank you in advance for any insight!
Jonas -
Hi and welcome to devnet,
I am not necessarily surprised of the order since there's no reason for a widget newly added to a layout to get inside the focus "path" already established.
One thing you could to is to add a method to your custom widgets were you give the previous and next widget and do the appropriate calls to setTabOrder. That way you would be independent of the layout itself.
-
Hi SGaist,
Thank you for your suggestion! I started to implement that, but I was then struggling with fixing the focus chain, as when I have A -> B and insert X before A, then X -> A works as expected, but A -> B no longer works.
The solution I found was to create a custom focus manager, and let only the desired widgets to register to the focus manager at their creation. I also overrided focusNextPrevChild on the relevant widget to request the focus manager to switch the focus to a sibling widget.
This solution has also the advantage that the logic of the focus management is in a dedicated class instead of in the widgets themselves.
If it can help anyone, I can also share my code.
Kind regards,
Jonas -
Nice solution !
Thanks for the offer :-)