How to delete an already existing layout on a widget?
Asked Answered
A

6

17

You must first delete the existing layout manager (returned by layout()) before you can call setLayout() with the new layout.

from http://doc.qt.io/qt-5.9/qwidget.html#setLayout

Which function is used for deleting the previous layout?

Advanced answered 23/9, 2011 at 12:6 Comment(0)
E
15

You just use

delete layout;

like you would with any other pointer you created using new.

Exhilarate answered 23/9, 2011 at 12:10 Comment(1)
this creates memory leaks, please see perden's answerEmbodiment
B
20

Chris Wilson's answer is correct, but I've found the layout does not delete sublayouts and qwidgets beneath it. It's best to do it manually if you have complicated layouts or you might have a memory leak.

QLayout * layout = new QWhateverLayout();

// ... create complicated layout ...

// completely delete layout and sublayouts
QLayoutItem * item;
QLayout * sublayout;
QWidget * widget;
while ((item = layout->takeAt(0))) {
    if ((sublayout = item->layout()) != 0) {/* do the same for sublayout*/}
    else if ((widget = item->widget()) != 0) {widget->hide(); delete widget;}
    else {delete item;}
}

// then finally
delete layout;
Been answered 27/9, 2011 at 13:26 Comment(2)
I believe this is incorrect because it will delete the children and the sublayouts if you pass the parent in their constructor.Chromaticness
Did you see any advantage in hiding the widget before deleting it or did you just want to be sure? I ask because I use delete without hide and would be interested in side-effects to comeEmbodiment
E
15

You just use

delete layout;

like you would with any other pointer you created using new.

Exhilarate answered 23/9, 2011 at 12:10 Comment(1)
this creates memory leaks, please see perden's answerEmbodiment
B
5

This code deletes the layout, all its children and everything inside the layout 'disappears'.

qDeleteAll(yourWidget->findChildren<QWidget *>(QString(), Qt::FindDirectChildrenOnly));
delete layout();

This deletes all direct widgets of the widget yourWidget. Using Qt::FindDirectChildrenOnly is essential as it prevents the deletion of widgets that are children of widgets that are also in the list and probably already deleted by the loop inside qDeleteAll.

Here is the description of qDeleteAll:

void qDeleteAll(ForwardIterator begin, ForwardIterator end)

Deletes all the items in the range [begin, end] using the C++ delete > operator. The item type must be a pointer type (for example, QWidget *).

Note that qDeleteAll needs to be called with a container from that widget (not the layout). And note that qDeleteAll does NOT delete yourWidget - just its children.

Now a new layout can be set.

Blacksmith answered 2/3, 2016 at 15:19 Comment(2)
The problem with this method is that you may end up accidentally deleting some attached QObject to yourWidget unrelated to layout/widget structure and this issue might be hard to find.Carbine
But you can filter the type (QWidget* in this case) and you can always perform another layer of filtering after having found the children. I think it's a great solutionPhobia
S
4

I want to remove the current layout, replace it with a new layout but keep all widgets managed by the layout. I found that in this case, Chris Wilson's solution does not work well. The layout is not always changed.

This worked for me:

void RemoveLayout (QWidget* widget)
{
    QLayout* layout = widget->layout ();
    if (layout != 0)
    {
    QLayoutItem *item;
    while ((item = layout->takeAt(0)) != 0)
        layout->removeItem (item);
    delete layout;
    }
}
Stench answered 20/8, 2012 at 9:4 Comment(1)
You should delete item; after layout->removeItem (item); or you will have memory leaks in your program. Check out perden answer.Chiliasm
C
3

From Qt6's docs:

The following code fragment shows a safe way to remove all items from a layout:

QLayoutItem *child;
while ((child = layout->takeAt(0)) != nullptr) {
    ...
    delete child->widget(); // delete the widget
    delete child;   // delete the layout item
}

This assumes takeAt() has been correctly implemented in the QLayout subclass. Follow link for details.

Cloven answered 16/7, 2022 at 8:40 Comment(0)
T
0

I had the issue today where I was trying to delete a layout of a widget to replace it with another. What happened was that the previous layout never disappeared inspite of the call to delete layout();.

So I figured out a very simple, effective and supported workaround by taking advantage of the fact that layouts cannot have more than one parent and can be reparented.

I created a deletePreviousLayout function:

void MyWidget::deletePreviousLayout()
{
    QWidget dummyWidget; // On the stack to deallocate it at the end of the function.
    dummyWidget.setLayout(layout()); // Reparenting
}

And that's it.

Thedathedric answered 22/1 at 4:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.