我在Qt中创建一个应用程序,允许用户在QGraphicsView中拖动各种“模块”。每当选择其中一个模块时,它会发出一个信号,然后由“ConfigurationWidget”拾取,这是一个侧面板,应该显示所选模块的所有相关参数:
class ConfigurationWidget : public QWidget
{
Q_OBJECT
public:
ConfigurationWidget(QWidget *parent) : QWidget(parent) {}
public slots:
void moduleSelected(Module* m)
{
if(layout())
{
while (itsLayout->count()>0)
{
delete itsLayout->takeAt(0);
}
}
delete layout();
itsLayout = new QFormLayout(this);
itsLayout->addRow(QString(tr("Type:")), new QLabel(m->name()));
itsLayout->addRow(QString(tr("Instance:")), new QLabel(m->instanceID()));
// ... Display a whole bunch of other fields that depends on the module
}
};
问题是当选择模块时,ConfigurationWidget实际上永远不会被清除。新字段只是绘制在旧字段上。我尝试过hide()和show(),invalidate(),update()等的各种组合无济于事。
制作可以动态改变其字段的小部件的正确方法是什么?
答案 0 :(得分:27)
我之前使用的代码循环如下:
void clearLayout(QLayout *layout) {
QLayoutItem *item;
while((item = layout->takeAt(0))) {
if (item->layout()) {
clearLayout(item->layout());
delete item->layout();
}
if (item->widget()) {
delete item->widget();
}
delete item;
}
}
希望这会对你有所帮助!
答案 1 :(得分:8)
如果将布局转移到堆栈上分配的另一个窗口小部件,则该布局中的窗口小部件将成为新窗口小部件的子窗口。当临时对象超出范围时,它会自动销毁布局及其中的所有小部件。
void moduleSelected(Module* m)
{
if(layout())
QWidget().setLayout(layout());
itsLayout = new QFormLayout(this);
itsLayout->addRow(QString(tr("Type:")), new QLabel(m->name()));
itsLayout->addRow(QString(tr("Instance:")), new QLabel(m->instanceID()));
// ... Display a whole bunch of other fields that depends on the module
}
答案 2 :(得分:4)
看起来最好的方法是使用QStackedLayout,正如armonge所暗示的那样:
void ConfigurationWidget::moduleSelectedSlot(Module* m)
{
QStackedLayout *stackedLayout = qobject_cast<QStackedLayout*>(layout());
QWidget *layoutWidget = new QWidget(this);
QFormLayout *formLayout = new QFormLayout(layoutWidget);
formLayout->addRow(QString(tr("Type:")), new QLabel(m->name()));
formLayout->addRow(QString(tr("Instance:")), new QLabel(m->instanceID()));
// ... Display a whole bunch of other fields that depends on the module
delete stackedLayout->currentWidget();
stackedLayout->addWidget(layoutWidget);
stackedLayout->setCurrentWidget(layoutWidget);
}
答案 3 :(得分:2)
使用while((item = layout->takeAt(0)))
将导致警告消息“无效索引为0”。
我使用count()
代替
void clearLayout(QLayout *layout)
{
if (layout) {
while(layout->count() > 0){
QLayoutItem *item = layout->takeAt(0);
QWidget* widget = item->widget();
if(widget)
delete widget;
delete item;
}
}
}
答案 4 :(得分:1)
我最近遇到了与QFormLayout相同的问题。 对我有用的(并且也在Qt的文档:http://qt-project.org/doc/qt-5/layout.html中)是takeAt(int)方法。
void clearLayout(QLayout *layout)
{
QLayoutItem *item;
while ((item = layout->takeAt(0)))
delete item;
}
答案 5 :(得分:1)
当您希望它们从窗口中消失时,将项重新显示为NULL。我最近遇到了类似的问题,重新解决了问题。
答案 6 :(得分:1)
到目前为止,我没有找到其他答案。它们要么崩溃要么不完全清除布局。因此,这就是我发现的工作原理,希望其他人对此有所帮助。
void eraseLayout(QLayout * layout)
{
while(layout->count() > 0)
{
QLayoutItem *item = layout->takeAt(0);
QWidget* widget = item->widget();
if(widget)
{
delete widget;
}
else
{
QLayout * layout = item->layout();
if (layout)
{
eraseLayout(layout);
}
else
{
QSpacerItem * si = item->spacerItem();
if (si)
{
delete si;
}
}
}
delete item;
}
}
答案 7 :(得分:0)
感谢Vaidotas Strazdas's commentary,我找到了可以正确重置布局的解决方案。使用deleteLater()
方法非常有效,否则delete
关键字会在刷新后的布局中导致大量的显示错误。
void resetLayout(QLayout* apLayout)
{
QLayoutItem *vpItem;
while ((vpItem = apLayout->takeAt(0)) != 0) {
if (vpItem->layout()) {
resetLayout(vpItem->layout());
vpItem->layout()->deleteLater();
}
if (vpItem->widget()) {
vpItem->widget()->deleteLater();
}
delete vpItem;
}
}