Removing QWidgets from a QGridLayout

10k views Asked by At

I have a QGridLayout where I add my custom QWidgets.

When I try to delete all of them they are supposedly removed from the layout (as the function layout.count() returns 0) but they are still shown in the interface and I can interact with them.

Here you have the way I add widgets:

void MyClass::addCustomWidget(CustomWidget *_widget, int r, int c)
{
    layout->addWidget(_widget, r, c);
    _widget->show();
}

And here the way I delete them:

void MyClass::clearLayout()
{
    qDebug() << "Layout count before clearing it: " << layout->count();

    int count = layout->count();
    int colums = layout->columnCount();
    int rows = layout->rowCount();

    int i=0;
    for(int j=0; j<rows; j++)
    {
        for(int k=0; k<colums && i<count; k++)
        {
            i++;

            qDebug() << "Removing item at: " << j << "," << k;
            QLayoutItem* item = layout->itemAtPosition(j, k);

            if (!item) continue;

            if (item->widget()) {
                layout->removeWidget(item->widget());
            } else {
                layout->removeItem(item);
            }
            qDebug() << "Removed!";
        }
    }

    qDebug() << "Layout count after clearing it: " << layout->count();
}

Any kind of help or tip to delete items/widgets correctly from a QGridLayout?

P.D. : I have seen on the internet that a lot of people deletes the widget directly (delete _widget) after removing them from the layout. In my case it is not possible as I need to mantain that widgets in memory.

5

There are 5 answers

1
Kamil Klimek On BEST ANSWER

Just to be clear. You didn't "delete" the widgets. You only removed them from layout. Removing from layout means only that widget will be no more managed (resized/positioned) by this layout BUT it doesn't mean that widget will be "deleted" (in C++ way). Also widget won't be magically hidden. Your widget after removing from layout still leaves in widget it was created / managed in. So owner of this layout still has this widget as child (visible child).

You have to

  1. hide widget or if you're sure it will not be used anymore

  2. delete widget with "delete" keyword

Also you don't need to call removeWidget(item->widget()); removeItem(item) will be enough for all layout items (even those with widget inside)

0
Alex Baum On

None of these answers worked for me. In my situation, I have several object each with their own QChartView. The idea is that the user selects which object they want to view and a common area central in the main window is updated with the QChartView of the user-selected object. This should have been straightforward, simply remove the widget from the chart area, add a new one. What ended up working for me was this:

while( QLayoutItem* item = ui->mPlotArea->layout()->takeAt(0) )
{
    item->widget()->setVisible(false);
    ui->mPlotArea->layout()->removeItem(item);
}

ui->mPlotArea->layout()->addWidget( pv );
pv->setVisible(true);

Where mPlotArea is a QFrame and pv is a derived class of QChartView. I can't explain why the other answers did not worked, but I spent a couple of hours trying different widgets and different ways of removing without deleting, organizing, etc...

0
UmNyobe On

Try

QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0);

It is supposed to be safe. If for any reasons it doesn't work, you can use a collection of widgets or layoutitems, which is updated every time you add a widget. Then to delete you loop on the collection and remove each element from the layout.

0
user2956496 On
Header:
class Grid : QGridLayout
{
public:
    Grid(QWidget* parent);
    void addElement(QWidget* element, int x, int y);
    void delElement(int x, int y);
    void resize(int width, int height);
    void clear();
protected:
    QSize size;
};

void Grid::clear(){
    for(int i = 0;i<size.width();i++){
        for(int j = 0;j<size.height();j++){
            QLayoutItem* item = takeAt(i*size.width() + j);
            if(item != NULL) delete item;
        }
    }
}
1
vdudouyt On

You can also use deleteLater() to avoid issue with maintaining child count during iterations:

for (int i = 0; i < gridLayout.count(); i++)
{
   gridLayout.itemAt(i)->widget()->deleteLater();
}