问题
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