Qt - remove all widgets from layout?

This does not seem simple. Basically, I add QPushButtons through the function to the layout, and when the function is executed, I want to clear the layout first (removing all QPushButtons and everything else there), because more buttons are just added to the scrollview.

heading

QVBoxLayout* _layout; 

caste

 void MainWindow::removeButtonsThenAddMore(const QString &item) { //remove buttons/widgets QVBoxLayout* _layout = new QVBoxLayout(this); QPushButton button = new QPushButton(item); _layout->addWidget(button); QPushButton button = new QPushButton("button"); _layout->addWidget(button); QWidget* widget = new QWidget(); widget->setLayout(_layout); QScrollArea* scroll = new QScrollArea(); scroll->setWidget(widget); scroll->show(); } 
+43
c ++ qt mobile qt4 nokia
Nov 24 '10 at
source share
12 answers

I had the same problem: I have a game application whose main window class inherits QMainWindow. Its constructor looks something like this:

 m_scene = new QGraphicsScene; m_scene->setBackgroundBrush( Qt::black ); ... m_view = new QGraphicsView( m_scene ); ... setCentralWidget( m_view ); 

When I want to display the level of the game, I create an instance of QGridLayout into which I add QLabels and then set their pixmaps for specific images (pixmaps with transparent parts). The first level displays well, but when switching to the second level, pixel images from the first level can still be seen behind the new ones (where the transparent map was transparent).

I tried a few things to remove old widgets. (a) I tried to remove the QGridLayout and create a new instance, but then I found out that deleting the layout does not delete the widgets added to it. (b) I tried calling QLabel :: clear () on the new pixmaps, but this, of course, only affected the new ones, not the zombies. (c) I even tried to delete my m_view and m_scene and restore them every time I displayed a new level, but still no luck.

Then (d) I tried one of the solutions above, namely

 QLayoutItem *wItem; while (wItem = widget->layout()->takeAt(0) != 0) delete wItem; 

but that didn't work either.

However, googling further, I found an answer that worked . What was missing in (d) was a call to delete item->widget() . Now the following works for me:

 // THIS IS THE SOLUTION! // Delete all existing widgets, if any. if ( m_view->layout() != NULL ) { QLayoutItem* item; while ( ( item = m_view->layout()->takeAt( 0 ) ) != NULL ) { delete item->widget(); delete item; } delete m_view->layout(); } 

and then I create a new QGridLayout, as in the first level, add new level widgets to it, etc.

Qt is a lot different in many ways, but I think these problems show that it might be a little easier here.

+33
May 7 '11 at 23:36
source share

Manage Layouts page in Qt help:

The layout will automatically display the widgets (using QWidget :: setParent ()) so that they are children of the widget on which the layout is installed. My conclusion: Widgets must be destroyed manually or by destroying the parent WIDGET, not the layout

Widgets in the layout are children of widgets on which the layout is installed, not the layout itself. Widgets can other widgets as parent, not layouts. My conclusion: Same as above

At @Muelner, for “controversy”, “Ownership of an item is transferred to the layout, and its layout is responsible for removing it.” - this does not mean WIDGET, but ITEM, which is re-represented in the layout and will be deleted later by the layout. Widgets are still children of the widget on which the layout is installed, and they must be removed manually or by removing the entire parent widget.

If you really need to remove all widgets and elements from the layout, leaving it completely empty, it needs to make a recursive function as follows: // Shallow verified, seems to work, but applies logic

 void clearLayout(QLayout* layout, bool deleteWidgets = true) { while (QLayoutItem* item = layout->takeAt(0)) { if (deleteWidgets) { if (QWidget* widget = item->widget()) widget.deleteLater(); } if (QLayout* childLayout = item->layout()) clearLayout(childLayout, deleteWidgets); delete item; } } 
+31
Aug 16 '11 at 11:16
source share

Missed: why not create a new layout, change it to the old layout and delete the old layout? This should remove all elements belonging to the layout and leave the rest.

Edit : after examining the comments on my answer, documentation and Qt sources, I found a better solution:

If you still support Qt3 support, you can use QLayout :: deleteAllItems (), which basically matches the hint in the documentation for QLayout :: takeAt:

The following code snippet shows a safe way to remove all elements from the layout:

 QLayoutItem *child; while ((child = layout->takeAt(0)) != 0) { ... delete child; } 

Change After further research, it seems that both versions above are equivalent: only sublanguages ​​and a widget without parents are deleted. Widgets with parents are considered in a special way. It seems that the TeL solution should work, you should be careful not to remove the top-level widgets. Another way would be to use a widget hierarchy to remove widgets: create a special widget without a parent and create all of your deleted widgets as a child of this special widget. After cleaning the layout, remove this special widget.

+6
Nov 25 '10 at 9:16
source share

I know this question is old and answered, but: Since QtAlgorithms offers qDeleteAll, you can delete the layout, including deleting all of its children using a single line. This code deletes the layout, all its children and everything inside the layout disappears.

 qDeleteAll(yourWidget->children()); 

Here is a description of the overloaded function:

void qDeleteAll (beginning of ForwardIterator, end of ForwardIterator)

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

Please note that qDeleteAll needs to be fed with a container from this widget (and not with this layout). Note that qDeleteAll does NOT delete yourWidget - only its children.

Now you can install a new layout.

+5
Mar 02 '16 at 15:18
source share

You also want you to remove spacers and things that are not QWidgets. If you are sure that the only things in your layout are QWidgets, the previous answer is fine. Otherwise, you should do this:

 QLayoutItem *wItem; while (wItem = widget->layout()->takeAt(0) != 0) delete wItem; 

It is important to know how to do this, because if the layout you want to clear is part of a larger layout, you do not want to destroy the layout. You want to make sure your layout maintains its place and relation to the rest of your window.

You must also be careful, you create a load of objects every time you call this method, and they are not cleared. First, you should probably create a QWidget and QScrollArea somewhere else, and save the member variable pointing to them for reference. Then your code might look something like this:

 QLayout *_layout = WidgetMemberVariable->layout(); // If it is the first time and the layout has not been created if (_layout == 0) { _layout = new QVBoxLayout(this); WidgetMemberVariable->setLayout(_layout); } // Delete all the existing buttons in the layout QLayoutItem *wItem; while (wItem = widget->layout()->takeAt(0) != 0) delete wItem; // Add your new buttons here. QPushButton button = new QPushButton(item); _layout->addWidget(button); QPushButton button = new QPushButton("button"); _layout->addWidget(button); 
+4
Nov 24 '10 at
source share

You are not writing about how to go the other way, but you can also just use QStackedWidget and add two views to it, one for each combination of buttons that you need. Scrolling between them is a problem without problems and a much lower risk than juggling various instances of dynamically created buttons

+2
Dec 06 '10 at 18:16
source share

None of the existing answers worked in my application. The modification of Darko Maximovich is still in effect. There he is:

 void clearLayout(QLayout* layout, bool deleteWidgets = true) { while (QLayoutItem* item = layout->takeAt(0)) { QWidget* widget; if ( (deleteWidgets) && (widget = item->widget()) ) { delete widget; } if (QLayout* childLayout = item->layout()) { clearLayout(childLayout, deleteWidgets); } delete item; } } 

It was necessary, at least with my hierarchy of widgets and layouts, to recursively remove widgets.

+2
Aug 28 '13 at 19:10
source share

only works for my button list if widget elements are also deleted. otherwise the old buttons are still visible:

 QLayoutItem* child; while ((child = pclLayout->takeAt(0)) != 0) { if (child->widget() != NULL) { delete (child->widget()); } delete child; } 
+2
Jan 29 '14 at
source share

I had a similar case when I have a QVBoxLayout containing a dynamically created QHBoxLayout object containing multiple QWidget instances. For some reason, I could not get rid of widgets without deleting either the top level of QVBoxLayout, or individual QHBoxLayouts. The only solution I came across was to go through the hierarchy and completely delete and delete everything:

 while(!vbox->isEmpty()) { QLayout *hb = vbox->takeAt(0)->layout(); while(!hb->isEmpty()) { QWidget *w = hb->takeAt(0)->widget(); delete w; } delete hb; } 
+1
Jun 15 '11 at 9:32 a.m.
source share

If you want to remove all widgets, you can do something like this:

 foreach (QObject *object, _layout->children()) { QWidget *widget = qobject_cast<QWidget*>(object); if (widget) { delete widget; } } 
0
Nov 24 '10 at
source share

If you are not doing anything funny when adding widgets to layouts and layouts in other layouts, they should all be reworked when adding to their parent widget. All QObjects have a deleteLater() slot, which will delete the object as soon as the control returns to the event loop. Widgets removed in this homestead also remove their children. So you just need to call deleteLater () for the highest item in the tree.

in hpp

 QScrollArea * Scroll; 

in cpp

 void ClearAndLoad(){ Scroll->widget()->deleteLater(); auto newLayout = new QVBoxLayout; //add buttons to new layout auto widget = new QWidget; widget->setLayout(newLayout); Scroll->setWidget(widget); } 

also note that in your example, _layout is a local variable and not the same as _layout in the header file (delete the QVBoxLayout* part). Also note that names starting with _ are reserved for developers of the standard library. I use trailing _, as in var_ , to show a local variable, there are many tastes, but the preceding _ and __ are technically reserved.

0
Oct 11 '13 at 15:48
source share

I have a possible solution to this problem (see Qt - clear all widgets inside a QWidget layout ). Remove all widgets and layouts in two different steps.

Step 1: Remove All Widgets

  QList< QWidget* > children; do { children = MYTOPWIDGET->findChildren< QWidget* >(); if ( children.count() == 0 ) break; delete children.at( 0 ); } while ( true ); 

Step 2: Remove All Layouts

  if ( MYTOPWIDGET->layout() ) { QLayoutItem* p_item; while ( ( p_item = MYTOPWIDGET->layout()->takeAt( 0 ) ) != nullptr ) delete p_item; delete MYTOPWIDGET->layout(); } 

After step 2, your MYTOPWIDGET should be clean.

0
Oct 21 '16 at 12:44
source share



All Articles