在 QT 的布局中插入小部件后修复 Tab 键顺序
我在 QT 5.5 中有一个自定义列表实现(QWidget
的子类).列表的元素使用 QVBoxLayout
进行组织.在运行时,元素(也是 QWidget
s)可以在布局中的任何位置动态添加到列表中或从列表中删除.这工作正常,除了一个细节:插入的可聚焦元素的制表符顺序错误.插入的最后一个元素始终是 Tab 键顺序中的最后一个元素,即使插入在其他两个元素之间也是如此.
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.
如何固定制表符顺序以表示布局顺序?我已经尝试遍历列表元素并在每个相邻对上使用 setTabOrder()
,但没有成功.
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.
关于实现的更多细节:
- 小部件不会直接添加到列表中.每次应添加小部件时,都会创建并添加一个代理小部件,真实"小部件将重新设置为代理的父级(代理正在执行一些图形操作).
QVBoxLayout::insertWidget()
用于插入代理小部件,然后调用QWidget::show()
- 移除元素时,元素会被隐藏,从代理中移除,代理从列表布局中移除并释放
- 可聚焦小部件可以位于添加到列表的元素对象树中的任何位置,它们不一定是元素本身
- Widgets are not added directly to the list. Each time a widget should be added, a proxy widget is created and added instead, the 'real' widget will be reparented to the proxy (The proxy is doing some graphic stuff).
QVBoxLayout::insertWidget()
is used to insert proxy widgets, followed by a call toQWidget::show()
- when removing elements, the element will be hidden, removed from the proxy, the proxy is removed from the list layout and deallocated
- focusable widgets can be anywhere in the object tree of elements which are added to the list, they are not necessarily the elements themselves
更新:添加了 MCVE!
以下缩小的示例演示了该问题.为了完整起见,我还包括了标题、主要功能和 .pro 文件.如果您不想重现问题,可以安全地跳过这些文件,TabOrderTestWindow.cpp 是重要的.
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
推荐答案
这似乎确实是一个错误,因为焦点代理将被处理的 Doc 状态.
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());
所以看来你需要做 Qt 应该为你做的事情.
So it seems you need to do what Qt should have done for you.
相关文章