About deleting, removing widgets and layouts in Qt 4
Asked Answered
L

2

23

(I use Qt 4.7, Windows 7, 64bit).

I created a custom table. Each row is a horizontal layout with widgets. The rows are kept in a QList for easy access, and the children too. The rows are also added inside the parent widget.

If I resize the parent widget, I calculate the new sizes, delete everything, and recreate it again.

My problem is that I don't want to delete any widget. Only when I clear the table, I do it.

Since I have the widgets inside a QList and inside the parent layouts, How can I remove all widgets in each row, delete all layouts, and then add those to new layouts?

If I do: takeAt(0) for every element inside each layout I have a QLayoutItem with a widget inside... How can I delete the layoutItem without deleting the widget?.... How do I remove the widget without killing it, no matter if it's in the parent or the child? Because there are many methods for deleting: removeItem, removeWidget... in a layout, but not takeWidget... just takeAt() and it gives a Qlayoutitem.

I tried several ways, but I still see the widgets no matter what happened to them.

Questions about this:

  • When does a widget get deleted? If I takeWidget(index) from a layout, is it deleted some time by itself? does it happen if I have a pointer to it in another list?

  • removeAt(index) does execute the delete method of a widget?

Locative answered 17/7, 2013 at 15:8 Comment(0)
M
33

Ok. I got it working. Let me explain how this Removing, keeping widgets works.

A widget is known by its parent layout. And you remove it through the layout. By doing:

layout()->removeAt(widget);
delete widget;

If you use takeAt(index) in a QLayout (or its children), it gives you a QLayoutItem. To access the widget inside, just use widget(). But there's no way to remove the widget without deleting it. So this approach is non valid.

In the Docs it tells a way to delete the elements:

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

A special thing to note in Qt is the following: If you have a hierarchy tree of layouts, added with addLayout() inside layouts, no matter how deep your widget is inserted, you can remove it from the child layouts or any of the parent layouts, if the tree path from the layout and this item is built from child layouts.

The easiest thing is to keep a list of pointers to all the items, in a custom table. When clearing the table to reconstruct it, just do this inside your widget:

  CustomTableItem* item;
  while ( !items_.isEmpty() && ( (item = items_.takeFirst()) != 0 ) ){
    layout()->removeWidget(item);
    delete item; // It works no matter where the item is
  }

  items_.clear(); // clear the list afterwards.

And it works perfectly, updates the layout too by itself. If you want to keep the elements, just skip the "delete item;" and use them afterwards.

An important thing to note is that different "remove" functions work differently (as i understand on Qt Docs) in QList or similar widgets, and in a QLayout.

In the QList, removeAt actually removes the object.

(Qt 4.7 QList Docs)"Removes the item at index position i. i must be a valid index position in the list (i.e., 0 <= i < size())."

In a QLayout, removeWidget or removeItem don't remove the item/widget, you have the responsability to delete it, as I did before.

(Qt 4.7 QLayout Docs) "Removes the widget widget from the layout. After this call, it is the caller's responsibility to give the widget a reasonable geometry or to put the widget back into a layout."

Hope it helps. If you see any error, you could tell me and I will edit the answer!

More on deleting here: Other stackoverflow post

Maible answered 17/7, 2013 at 15:8 Comment(4)
layout()->removeAt(widget); does ONLY exist for QGraphicsLayout. What you mean is probably layout()->removeWidget(widget);Hyehyena
That is also what you can do to remove a widget from a layout WITHOUT deleting it. If you do not have the widget pointer, do the following: QLayoutItem * item = layout->itemAt(0); QWidget * widget = item->widget(); if (widget != NULL) { layout->removeWidget(widget); //if you want to delete the widget, do: widget->setParent(NULL); delete widget; } (formatting does not work, but you get the idea...)Hyehyena
FYI: This is not valid in Python since you have to take care of the internal c++ object too .Locative
When the item needs to be destroyed from an event handler (slot), it is necessary to call item->deleteLater() as is shown in the "other post"., otherwise a heap corruption will occur.Tephra
A
9

A widget in Qt is a regular C++ object and can be deleted with the C++ delete operator as any other object:

delete myWidget;

In Qt there is always a parent-child relation between widgets. When the parent widget is destroyed, it will delete all its children. Usually, you do not need to think about explicitly deleting any widgets but the top level widgets, i.e., windows and dialogs. Qt will take care of deleting any child widgets.

QList::removeAt(int) does not delete the object that is removed, it only removes the object from the list. If you also want to delete the object you would have to do something like:

delete myList.takeAt(0);

This applies to all functions such as removeAt(int), takeAt(int), takeFirst(), etc. They never delete objects, they only remove them from the container (list, layout, scrollarea, etc). In most cases the ownership of the widget is then transferred to the caller, (the caller becomes responsible for deleting the widget as the parent-child relation breaks), but do not assume this is always the case, always read the documentation of the function.

Amphiarthrosis answered 17/7, 2013 at 18:30 Comment(2)
Thanks! But what about my particular problem: I have a QBoxLayout. I do: takeAt(int) to take an element. It´s not a widget, but a QLayoutItem. To take the widget i use. widget(void) function. But the widget remains inside. How do i take out the widget and delete that LayoutItem? There´s no function for that!Locative
FYI This is not valid in Python. You have to take care of the internal c++ object too.Locative

© 2022 - 2024 — McMap. All rights reserved.