qgridlayout添加和删除子布局

时间:2018-07-18 07:37:31

标签: c++ qt layout

不幸的是,我发现的这个问题的答案对我不起作用。我想我在某个地方犯了错误...

我想向QGridLayout添加内容:

int rows = 2;
int columns = 2;
for(int i=0; i<rows; ++i){
    for(int j=0; j<columns; ++j){
        QVBoxLayout *layout = new QVBoxLayout();
        QComboBox *c1 = new QComboBox();
        QComboBox *c2 = new QComboBox();
        layout->addWidget(c1);
        layout->addWidget(c2);
        ui->gridLayout->addLayout(layout,i,j);
    }
}

我现在想更改此QGridLayout的内容。 因此,我首先要删除此布局中已经存在的所有内容。 我试图为此工作编写一个函数:

我尝试了几种方法,但从未删除旧的组合框:

void VieSchedpp_Analyser::setLayout(int rows, int columns){

    qDeleteAll(ui->gridLayout->children());

    for(int i=0; i<rows; ++i){
        for(int j=0; j<columns; ++j){
            QVBoxLayout *layout = new QVBoxLayout();
            QComboBox *c1 = new QComboBox();
            QComboBox *c2 = new QComboBox();
            layout->addWidget(c1);
            layout->addWidget(c2);
            ui->gridLayout->addLayout(layout,i,j);
        }
    }
}

void VieSchedpp_Analyser::setLayout(int rows, int columns){

    while( ui->gridLayout->count() >0){
        auto itm = ui->gridLayout->takeAt(0);
        if(itm->widget()){
            delete itm->widget();
        }
        if(itm->layout()){
           delete itm->layout();
        }
    }

    for(int i=0; i<rows; ++i){
        for(int j=0; j<columns; ++j){
            QVBoxLayout *layout = new QVBoxLayout();
            QComboBox *c1 = new QComboBox();
            QComboBox *c2 = new QComboBox();
            layout->addWidget(c1);
            layout->addWidget(c2);
            ui->gridLayout->addLayout(layout,i,j);
        }
    }
}

2 个答案:

答案 0 :(得分:2)

我花了一段时间来重现OP的问题,但最终我明白了:

嵌套布局使事情变得更加复杂。为解决此问题,应递归清除布局。

在玩这个游戏的时候,我对样本进行了很多诊断。这让我想起了

  • 小部件的父级是布局的父级小部件
  • 但布局的父级是父级布局或小部件。

我在示例代码中将诊断信息保留为注释。 我的示例应用程序:

onActivityResult

输出:

#include <QtWidgets>

class Label: public QLabel {
  public:
    Label(const QString &text): QLabel(text) { }
    virtual ~Label() { qDebug() << "Destroyed:" << this << text(); }
};

class VBoxLayout: public QVBoxLayout {
  public:
    VBoxLayout() = default;
    virtual ~VBoxLayout() { qDebug() << "Destroyed:" << this; }
};

void clearLayout(QLayout &qGrid)
{
  for (int i = qGrid.count(); i--;) {
    QLayoutItem *pQLItem = qGrid.takeAt(i);
    if (QWidget *pQWidget = pQLItem->widget()) {
#if 0 // diagnostics
      qDebug()
        << dynamic_cast<QLabel*>(pQWidget)->text() << ".parent():"
        << pQWidget->parent();
#endif // 0
      delete pQWidget;
      delete pQLItem;
    } else if (QLayout *pQLayout = pQLItem->layout()) {
      clearLayout(*pQLayout);
      delete pQLayout;
    }
  }
}

void fillLayout(QGridLayout &qGrid)
{
  static unsigned id;
  int w = 1 + qrand() % 3, h = 1 + qrand() % 3;
  for (int y = 0; y < h; ++y) {
    for (int x = 0; x < w; ++x) {
      if (qrand() & 1) {
        QVBoxLayout *pQVBox = new VBoxLayout();
        pQVBox->addWidget(
          new Label(QString("Label %1").arg(++id)));
        pQVBox->addWidget(
          new Label(QString("Label %1").arg(++id)));
        qGrid.addLayout(pQVBox, y, x);
      } else {
        qGrid.addWidget(
          new Label(QString("Label %1").arg(++id)),
          y, x);
      }
    }
  }
#if 0 // diagnostics
  qDebug() << "qGrid.parent().children().count():"
    << dynamic_cast<QWidget*>(qGrid.parent())->children().count();
  qDebug() << "qGrid.parent().children():"
    << dynamic_cast<QWidget*>(qGrid.parent())->children();
#endif // 0
}

int main(int argc, char **argv)
{
  QApplication app(argc, argv);
  // setup GUI
  QWidget qWin;
  qWin.setWindowTitle(QString::fromUtf8("Demo Delete from QGridLayout"));
  QGridLayout qGrid;
  qWin.setLayout(&qGrid);
  qWin.show();
#if 0 // diagnostics
  qDebug() << "qGrid.parent():" << &qWin;
#endif // 0
  fillLayout(qGrid);
  // install timer
  QTimer qTimer;
  qTimer.setInterval(10000 /* ms */);
  QObject::connect(&qTimer, &QTimer::timeout,
    [&]() { clearLayout(qGrid); fillLayout(qGrid); });
  qTimer.start();
  // runtime loop
  return app.exec();
}

快照:

snapshot of testQDeleteFromLayout

如果排除了Destroyed: QLabel(0x1df10113a30) "Label 11" Destroyed: QLabel(0x1df10112c70) "Label 10" Destroyed: QVBoxLayout(0x1df10110d10) Destroyed: QLabel(0x1df100caa90) "Label 9" Destroyed: QLabel(0x1df1010ae60) "Label 8" Destroyed: QLabel(0x1df1010fc80) "Label 7" Destroyed: QLabel(0x1df100ca810) "Label 6" Destroyed: QLabel(0x1df1010dfa0) "Label 5" Destroyed: QLabel(0x1df1010cd30) "Label 4" Destroyed: QLabel(0x1df100ca9e0) "Label 3" Destroyed: QVBoxLayout(0x1df101095a0) Destroyed: QLabel(0x1df1010af40) "Label 2" Destroyed: QLabel(0x1df10109f40) "Label 1" Destroyed: QLabel(0x1df1010d5f0) "Label 22" Destroyed: QLabel(0x1df1010c830) "Label 21" Destroyed: QVBoxLayout(0x1df1010e450) Destroyed: QLabel(0x1df1010e3b0) "Label 20" Destroyed: QLabel(0x1df10111d60) "Label 19" Destroyed: QLabel(0x1df1010f6f0) "Label 18" Destroyed: QVBoxLayout(0x1df1010f4f0) Destroyed: QLabel(0x1df101133d0) "Label 17" Destroyed: QLabel(0x1df101117b0) "Label 16" Destroyed: QVBoxLayout(0x1df101115b0) Destroyed: QLabel(0x1df101144d0) "Label 15" Destroyed: QLabel(0x1df1010a0b0) "Label 14" Destroyed: QVBoxLayout(0x1df101130e0) Destroyed: QLabel(0x1df100ca810) "Label 13" Destroyed: QLabel(0x1df100f1310) "Label 12" Destroyed: QVBoxLayout(0x1df101095a0) Destroyed: QLabel(0x1df100f1310) "Label 23" Destroyed: QLabel(0x1df1010b4f0) "Label 27" Destroyed: QLabel(0x1df1010a0b0) "Label 26" Destroyed: QVBoxLayout(0x1df101095a0) Destroyed: QLabel(0x1df100d07e0) "Label 25" Destroyed: QLabel(0x1df100f1310) "Label 24" 的递归调用行,则仅删除最顶层布局的窗口小部件,而不删除嵌套布局中的窗口小部件(尽管布局本身被删除/删除)。原因:这些后面的小部件仍然是父小部件的子代。 (我不知道这些小部件的父级布局已删除后如何处理。实际上,我试图防止这种情况在生产性软件中发生。)

要清除的快照快照:

snapshot of broken testQDeleteFromLayout (without recursive clearing of layouts)

我在Visual Studio 2013(Window 10 64位)中使用Qt 5.9.2编译了示例。

我也在cygwin64中尝试了类似的结果。

对于cygwin,我使用了以下项目文件:

clearLayout()

答案 1 :(得分:0)

您正在从ui->gridLayout_skyCoverage删除项目,但新项目已添加到ui->gridLayout

更新

可能您应该删除项目本身,而不是其layout()widget()(请参阅QLayout::takeAt