清除Qt中的布局

问题描述 投票:12回答:7

我正在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()等各种组合无济于事。

制作可以动态改变其字段的小部件的正确方法是什么?

c++ qt qt4
7个回答
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;
    }
}

希望这对你有所帮助!


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
}

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);
}

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;
        }
    }
}

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;
}

1
投票

当您希望它们从窗口中消失时,将项重新显示为NULL。我最近遇到了类似的问题,重新解决了这些问题。


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;
    }
}

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;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.