I have a custom list implementation (a subclass of QWidget
) in QT 5.5. The elements of the list are organized using a QVBoxLayout
. At runtime, elements (which are also QWidget
s) can be dynamically added to and removed from the list at any position in the layout. This is working fine, except for one detail: the tab order of inserted focusable elements is wrong. The last element inserted will always be the last in the tab order, even if inserted in between two other elements.
How can I fix the tab order to represent the layout order? I already tried iterating over the list elements and using setTabOrder()
on each adjacent pair, without success.
A few more details on the implementation:
QVBoxLayout::insertWidget()
is used to insert proxy widgets, followed by a call to QWidget::show()
Update: Added a MCVE!
The following minified example demonstrates the problem. For completeness, I also included the headers, main function, and .pro file. You can safely skip those files if you don't want to reproduce the issue, TabOrderTestWindow.cpp is the important one.
TabOrderTestWindow.cpp:
#include "TabOrderTestWindow.h"
#include <QVBoxLayout>
#include <QPushButton>
// create a button inside a proxy widget
QWidget* createButtonProxy(const QString& caption, QWidget* parent) {
QWidget* proxy = new QWidget(parent);
QPushButton* button = new QPushButton(caption, proxy);
proxy->setFocusProxy(button);
return proxy;
}
TabOrderTestWindow::TabOrderTestWindow()
: QWidget()
{
setMinimumHeight(200);
setMinimumWidth(350);
QVBoxLayout* layout = new QVBoxLayout(this);
// create and add 3 buttons in order
QWidget* button1 = createButtonProxy("button 1", this);
QWidget* button2 = createButtonProxy("button 2", this);
QWidget* button3 = createButtonProxy("button 3", this);
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
// now insert a fourth button in between the others - incorrect tab order!
QWidget* buttonInbetween = createButtonProxy("button in between", this);
layout->insertWidget(1, buttonInbetween);
// attempt to correct tab order - not working, even with focus proxy set...
setTabOrder(button1, buttonInbetween);
setTabOrder(buttonInbetween, button2);
}
TabOrderTestWindow.h:
#ifndef TABORDERTESTWINDOW_H
#define TABORDERTESTWINDOW_H
#include <QMainWindow>
class TabOrderTestWindow : public QWidget
{
Q_OBJECT
public:
TabOrderTestWindow();
};
#endif // TABORDERTESTWINDOW_H
main.cpp:
#include "TabOrderTestWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TabOrderTestWindow w;
w.show();
return a.exec();
}
TabOrderTest.pro:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = TabOrderTest
TEMPLATE = app
SOURCES += main.cpp\
TabOrderTestWindow.cpp
HEADERS += TabOrderTestWindow.h
To enter tab order editing mode, open the Edit menu and select Edit Tab Order. In this mode, each input widget in the form is shown with a number indicating its position in the tab order.
Right-click the relevant widget and select Layout alignment > Top.
The normal way to use QTabWidget is to do the following: Create a QTabWidget. Create a QWidget for each of the pages in the tab dialog, but do not specify parent widgets for them. Insert child widgets into the page widget, using layouts to position them as normal.
Qt Widgets provide means for customization via style sheets, but Qt Quick is a better performing choice for user interfaces that do not aim to look native. Qt Widgets do not scale well for animations. Qt Quick offers a convenient and natural way to implement animations in a declarative manner.
Here really seems to be a bug as the Doc state that focus proxies would be cared of.
But we can care of them ourself by using:
setTabOrder(button1->focusProxy(), buttonInbetween->focusProxy());
setTabOrder(buttonInbetween->focusProxy(), button2->focusProxy());
So it seems you need to do what Qt should have done for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With