qgridlayout add and remove sub layouts

岁酱吖の 提交于 2021-01-28 09:13:08

问题


unfortunately, the answers to this question that I have found do not work for me. I think I make a mistake somewhere...

I want to add content to a 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);
    }
}

I now want to change the content of this QGridLayout. Therefore I first want to delete everything that is already in this layout. I tried to write a function for this job:

I tried several approaches like but the old combo boxes are never deleted:

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

or

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

回答1:


I struggled a while to reproduce the issue of OP but finally I got it:

The nested layouts make things a bit more complicated. To solve this the layouts should be cleared recursively.

While playing with this I put a lot of diagnostics into my sample. This remembered me that

  • parent of a widget is the parent widget of layout
  • but parent of a layout is the parent layout or widget.

I left the diagnostics as comments in the sample code. My sample application:

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

Output:

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:

If the line for recursive call of clearLayout() is excluded then only widgets of the top-most layout are removed but not the one in the nested layout (though the layout itself is removed/deleted). The reason: These latter widgets are still children of the parent widget. (I have no idea how these widgets are handled after their parent layout has been removed. Actually, I try to prevent such scenarios in productive S/W.)

Snapshot for broken clearing:

I compiled the sample with Qt 5.9.2 in VisualStudio 2013 (Window 10 64 Bit).

I tried also in cygwin64 with similar results.

For cygwin, I used the following project file:

SOURCES = testQDeleteFromLayout.cc

QT += widgets



回答2:


You are removing item from the ui->gridLayout_skyCoverage but new one is added to ui->gridLayout.

Update

Probably, you should delete an item itself, not its layout() or widget() (see QLayout::takeAt)



来源:https://stackoverflow.com/questions/51396216/qgridlayout-add-and-remove-sub-layouts

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!