path: root/src
diff options
authorIvan Solovev <>2021-01-11 19:24:42 +0100
committerIvan Solovev <>2021-01-14 20:09:43 +0100
commit00505ed2b57d0a6911c8274af2bff883a93f583a (patch)
tree8d06de7ae3b553ced949b7d0b08d71faedc37ee2 /src
parentaeeac48cbdea744406f0c8abefe271f571b61d07 (diff)
Widgets: fix setTabOrder for QAbstractSpinBox-like widgets
setTabOrder was not considering the case, when a child widget has its focus proxy set to its parent widget. This happens, for example, for the QLineEdit that is nested inside the QAbstractSpinBox. For such cases the lastFocusChild was calculated incorrectly, and, as a result, such child widgets were not correctly positioned in the focus chain. This could lead to an error while backtabbing. Here is a brief example. Suppose we have 3 widgets arranged like this: auto spinBoxOne = new QDoubleSpinBox; auto spinBoxTwo = new QDoubleSpinBox; auto button = new QPushButton; Then the default widget focus order is: - spinBoxOne - lineedit (from spinBoxOne) - spinBoxTwo - lineedit (from spinBoxTwo) - button Before this commit setting the explicit tab order changed the focus order in the following way: QWidget::setTabOrder(spinBoxOne, spinBoxTwo); QWidget::setTabOrder(spinBoxTwo, button); - spinBoxOne - spinBoxTwo - button - lineedit (from spinBoxOne) - lineedit (from spinBoxTwo) In this case, backtabbing from spinBoxOne actually leads us to lineedit (from spinBoxTwo), which refers to spinBoxTwo. And so we're stuck in a loop. This commit fixes the issue by handling such special case, and preserving correct focus order. Note: the actual unit-test in this patch uses QLineEdit instead of QPushButton, because one can't tab to buttons on macOS by default. However the general idea is the same. Pick-to: 6.0 5.15 Fixes: QTBUG-81097 Change-Id: I5d16da7733a4d63f809cab28b8ca9e116b87cffa Reviewed-by: Volker Hilsheimer <>
Diffstat (limited to 'src')
1 files changed, 14 insertions, 1 deletions
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 023a987dc4..b4be9bbfe7 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -6774,8 +6774,21 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second)
lastFocusChild = target;
QWidget *focusProxy = target->d_func()->deepestFocusProxy();
- if (!focusProxy || !target->isAncestorOf(focusProxy))
+ if (!focusProxy || !target->isAncestorOf(focusProxy)) {
+ // QTBUG-81097: Another case is possible here. We can have a child
+ // widget, that sets its focusProxy() to the parent (target).
+ // An example of such widget is a QLineEdit, nested into
+ // a QAbstractSpinBox. In this case such widget should be considered
+ // the last focus child.
+ for (auto *object : target->children()) {
+ QWidget *w = qobject_cast<QWidget*>(object);
+ if (w && w->focusProxy() == target) {
+ lastFocusChild = w;
+ break;
+ }
+ }
+ }
lastFocusChild = focusProxy;