Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do you need to delete widget after removeItemWidget from QTreeWidget?

I have a QTreeWidget with two columns: one for property name and one for property value. The value can be edited via a widget. For example one property is Animal. When you double click the property value column I make a (custom) combobox with different animal types via this code:

QTreeWidgetItemComboBox* comboBox = new QTreeWidgetItemComboBox(treeItem, 1); 
// treeitem is a pointer to the row that is double clicked
comboBox->addItems(QStringList() << "Bird" << "Fish" << "Ape");
ui.treeWidget->setItemWidget(treeItem, 1, comboBox);

When the row loses focus I remove the widget again (and the value is put as text of the QTreeWidgetItem). For removing I use

ui.treeWidget->removeItemWidget(treeItem, 1);

Now I'm wondering, since I've used new, do I neww to also delete the widget. I know this is the case if you use takeChild(i) for example. But I didn't see something similar for an itemWidget.

Do I need to delete it what would be the right order?

QTreeWidgetItemComboBox* comboBox = ui.treeWidget->itemWidget(treeItem,1); 
// Do I need a cast here since the return type is QWidget*
ui.treeWidget->removeItemWidget(treeItem, 1);
delete comboBox;

or

QTreeWidgetItemComboBox* comboBox = ui.treeWidget->itemWidget(treeItem,1); 
// Do I need a cast here since the return type is QWidget*
delete comboBox;
ui.treeWidget->removeItemWidget(treeItem, 1);
like image 655
C. Binair Avatar asked Jan 26 '23 18:01

C. Binair


2 Answers

When the widget is added ot the QTreeWidget, it indeed takes ownership of the widget. But it only implies that the widget will be deleted when the parent is destroyed.

So if you just want to remove the widget while keeping the parent QTreeWidget alive, you indeed have to delete it manually.

The correct solution is the first one, remove the widget from the QTreeWidget first, and then delete it with one of the following ways:

delete comboBox;
comboBox = nullptr;

or:

comboBox.deleteLater();

The second one is preferred.


EDIT:

I don't change the answer since it could be a dishonest to change what was already accepted, ...

But as @Scopchanov mentioned, by reading the source code, the QTreeWidget::removeItemWidget() already calls the deleteLater() method on the old widget. We don't have to do it manually.

Anyway, the documentation says it is safe to call deleteLater() more than once:

Note: It is safe to call this function more than once; when the first deferred deletion event is delivered, any pending events for the object are removed from the event queue.

Therefore, manually deleting the widget after calling QTreeWidget::removeItemWidget() becomes useless.

like image 65
Fareanor Avatar answered Feb 05 '23 16:02

Fareanor


You are not allowed to delete the item widget as the tree is the owner of the widget once it has been passed to the tree with setItemWidget().

From the documentation of setItemWidget():

Note: The tree takes ownership of the widget.

EDIT: In case you want a new widget, simply call setItemWidget() once more or call removeItemWidget() in case you do not need the widget anymore. The tree will ensure that no memory gets lost.

like image 33
Jens Avatar answered Feb 05 '23 17:02

Jens