Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way to cleanup widgets in pyqt

Tags:

pyqt

pyqt4

What is the 'correct' or idiomatic way to cleanup/delete widgets when using PyQt4?

Consider the following code:

choices = ['a', 'b', 'c']
checkboxes = []
layout = QtGui.QVBoxLayout()

dialog = MyDialog()

for c in choices:
    checkboxes.append(QtGui.QCheckBox(c)
    layout.addWidget(chkbox)

dialog.setLayout(layout)

for c in checkboxes:
    c.setParent(None)
    c.deleteLater()
    c = None

The above code uses setParent(), deleteLater(), and setting the object to None. Are all of these necessary?

Another possible scenario is I have a dialog with a bunch of widgets on it and want to remove these widgets and add new ones. I don't want to 'leak' the old widgets, but I'm not sure what the correct way to do something like this would be.

It seems to me that deleteLater() might never be needed. Does it just decrement the reference count? If so, wouldn't just setting the variable to None do the same thing?

like image 535
durden2.0 Avatar asked Dec 11 '12 20:12

durden2.0


People also ask

How do I remove a widget from Qt?

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().

What is a widget in PyQt?

In Qt (and most User Interfaces) 'widget' is the name given to a component of the UI that the user can interact with. User interfaces are made up of multiple widgets, arranged within the window.

What is layout in PyQt?

In PyQt, layout managers are classes that provide the required functionality to automatically manage the size, position, and resizing behavior of the widgets in the layout. With layout managers, you can automatically arrange child widgets within any parent, or container, widget.


1 Answers

First thing you should remember to do is to use the parent/child relationships for your widgets. When you do this, they will be owned by Qt and will automatically clean up all children when the parent is deleted.

dialog = MyDialog()

for c in choices:
    checkboxes.append(QtGui.QCheckBox(c, parent=dialog))
    layout.addWidget(chkbox)

In this situation, all the checkboxes will be properly cleaned up when you delete dialog. This handles one part of your question. I realize that you are implicitly having the parent set when you add them to the layout. But you should not then clear that parent before deleting. It is the parent relationship that allows the child to be automatically removed. Not a reference count. The reference aspect would be a python-side thing where it will get garbage collected when there are no more references to it.

deleteLater is very important, for use when you want the deletion to occur when control returns to the eventloop. It is also the safe way to delete widgets when you are removing some from a layout and adding new ones:

# clear a layout and delete all widgets
# aLayout is some QLayout for instance
while aLayout.count():
    item = aLayout.takeAt(0)
    item.widget().deleteLater()

These widgets will actually be deleted once this method has completed. deleteLater is also useful for deleting the widget under which the slot or event is currently occurring. Such as a QPushButton that can delete itself on click.

There is also not much need to set c = None. Once a parent is deleted, and that triggers the deletion of all of its children, recursively, your python references to that object will be invalid. So all you need to do is to just not use them anymore. If they are in a list, clear the list. Accessing them would raise the RuntimeError: wrapped C/C++ object of %S has been deleted meaning they are deleted.

like image 160
jdi Avatar answered Jan 02 '23 05:01

jdi