如何根据同一布局中的另一个小部件将添加的小部件定位到布局?
How to position an added widget to a layout based on another widget in the same layout?
在我的 GUI 中,我想根据特定操作触发的信号以编程方式将 QComboBox
添加到 verticalLayout
。以下代码工作正常并添加了小部件:
QComboBox* userOptions = new QComboBox();
ui->verticalLayout_13->addWidget(userOptions);
但是,这种方式总是将小部件添加到布局的末尾。
我的问题是:如何将添加的 QComboBox
定位到 verticalLayout
与同一布局中的另一个小部件对齐? (即:例如 "Go" 按钮上方)
似乎没有办法在您想要的布局中明确插入项目。
您有几种选择可以实现 "hard" 方式:
- 使用
QLayout::takeAt(int index)
获取您要插入的索引后的所有项目,插入您的项目,然后再插入取回的项目。
- 创建一个占位符小部件,您可以使用它在布局中保留索引,然后您不会将项目插入布局中,而是插入嵌套在占位符小部件内的布局中。如果没有项目,占位符小部件将不占用 space,并会扩展以容纳放入其中的任何内容。
- 实现您自己的
QLayout
支持在特定索引处插入的子类。您必须实现几个功能。
编辑:正如 Kuba Ober 指出的那样,我的遗漏是,大多数具体布局实现都支持在特定索引处插入,例如 QBoxLayout
派生具有将索引作为参数传递的插入方法。
首先,迭代布局以找到您要插入的参考项的索引。然后使用具体布局的特定小部件 insertion/addition 功能。
由于您大概使用 QBoxLayout
,因此您将使用它的 insertWidget
方法来插入小部件。
// https://github.com/KubaO/Whosebugn/tree/master/questions/insert-widget-36746949
#include <QtWidgets>
namespace SO { enum InsertPosition { InsertBefore, InsertAfter }; }
bool insertWidget(QBoxLayout * layout, QWidget * reference, QWidget * widget,
SO::InsertPosition pos = SO::InsertBefore, int stretch = 0,
Qt::Alignment alignment = 0) {
int index = -1;
for (int i = 0; i < layout->count(); ++i)
if (layout->itemAt(i)->widget() == reference) {
index = i;
break;
}
if (index < 0) return false;
if (pos == SO::InsertAfter) index++;
layout->insertWidget(index, widget, stretch, alignment);
return true;
}
可以很容易地为 QFormLayout
、QGridLayout
和 QStackedLayout
设计类似的函数。
还有一个测试工具:
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QWidget w;
QVBoxLayout l{&w};
QLabel first{"First"};
QLabel second{"Second"};
l.addWidget(&first);
l.addWidget(&second);
insertWidget(&l, &first, new QLabel{"Before First"}, SO::InsertBefore);
insertWidget(&l, &second, new QLabel{"After Second"}, SO::InsertAfter);
w.show();
return app.exec();
}
在我的 GUI 中,我想根据特定操作触发的信号以编程方式将 QComboBox
添加到 verticalLayout
。以下代码工作正常并添加了小部件:
QComboBox* userOptions = new QComboBox();
ui->verticalLayout_13->addWidget(userOptions);
但是,这种方式总是将小部件添加到布局的末尾。
我的问题是:如何将添加的 QComboBox
定位到 verticalLayout
与同一布局中的另一个小部件对齐? (即:例如 "Go" 按钮上方)
似乎没有办法在您想要的布局中明确插入项目。
您有几种选择可以实现 "hard" 方式:
- 使用
QLayout::takeAt(int index)
获取您要插入的索引后的所有项目,插入您的项目,然后再插入取回的项目。 - 创建一个占位符小部件,您可以使用它在布局中保留索引,然后您不会将项目插入布局中,而是插入嵌套在占位符小部件内的布局中。如果没有项目,占位符小部件将不占用 space,并会扩展以容纳放入其中的任何内容。
- 实现您自己的
QLayout
支持在特定索引处插入的子类。您必须实现几个功能。
编辑:正如 Kuba Ober 指出的那样,我的遗漏是,大多数具体布局实现都支持在特定索引处插入,例如 QBoxLayout
派生具有将索引作为参数传递的插入方法。
首先,迭代布局以找到您要插入的参考项的索引。然后使用具体布局的特定小部件 insertion/addition 功能。
由于您大概使用 QBoxLayout
,因此您将使用它的 insertWidget
方法来插入小部件。
// https://github.com/KubaO/Whosebugn/tree/master/questions/insert-widget-36746949
#include <QtWidgets>
namespace SO { enum InsertPosition { InsertBefore, InsertAfter }; }
bool insertWidget(QBoxLayout * layout, QWidget * reference, QWidget * widget,
SO::InsertPosition pos = SO::InsertBefore, int stretch = 0,
Qt::Alignment alignment = 0) {
int index = -1;
for (int i = 0; i < layout->count(); ++i)
if (layout->itemAt(i)->widget() == reference) {
index = i;
break;
}
if (index < 0) return false;
if (pos == SO::InsertAfter) index++;
layout->insertWidget(index, widget, stretch, alignment);
return true;
}
可以很容易地为 QFormLayout
、QGridLayout
和 QStackedLayout
设计类似的函数。
还有一个测试工具:
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QWidget w;
QVBoxLayout l{&w};
QLabel first{"First"};
QLabel second{"Second"};
l.addWidget(&first);
l.addWidget(&second);
insertWidget(&l, &first, new QLabel{"Before First"}, SO::InsertBefore);
insertWidget(&l, &second, new QLabel{"After Second"}, SO::InsertAfter);
w.show();
return app.exec();
}