Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PySide: Removing a widget from a layout

I'm trying to remove a Qt widget from a layout in a PySide application.

Here is a minimal example. It is a widget with 5 buttons in it, and the middle one is supposed to remove itself when clicked:

import sys
from PySide import QtGui

app = QtGui.QApplication(sys.argv)
widget = QtGui.QWidget()
layout = QtGui.QVBoxLayout()
buttons = [QtGui.QPushButton(str(x)) for x in xrange(5)]

def deleteButton():
    b = layout.takeAt(2)
    buttons.pop(2)
    del b
buttons[2].clicked.connect(deleteButton)

map(layout.addWidget, buttons)
widget.setLayout(layout)
widget.show()
app.exec_()

What actually happens is this:

What actually happens

The button is unclickable and clearly isn't taken into consideration for the layout computations, but its image stays in place.

According to the Qt documentation, the correct way of deleting all objects from a layout is:

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

Here I just want to delete the third button, so I just call takeAt(2), and then del b to call the destructor on that item. The button object is also .pop'd from the buttons list to make sure there is no leftover reference to the object. How does my code differ from the one in the Qt docs that would cause such a behavior?

like image 568
Etienne Perot Avatar asked Mar 28 '12 00:03

Etienne Perot


People also ask

How do I hide Qwidget?

Show() and hide() widget Each Qt widget has a . setVisible method which can be used to toggle that widget's visibility. >> However, compound or nested widgets can only become invisible when all their child widgets are >>also invisible.

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.

How do I delete a layout element?

Deleting a Layout Element. To delete a layout element from an attribute layout, right-click the actions menu for the layout element information pane and select Delete Group. Inherited layout elements cannot be deleted, but new layout elements added to an inherited layout can be deleted.

How do I remove a widget in Python?

We can delete widgets from the window or frame using the . destroy method in tkinter. It can be invoked in the widget by defining a function for it.


1 Answers

Super simple fix:

def deleteButton():     b = layout.takeAt(2)     buttons.pop(2)     b.widget().deleteLater() 

You first have to make sure you are addressing the actual button and not the QWidgetItem that is returned from the layout, and then call deleteLater() which will tell Qt to destroy the widget after this slot ends and control returns to the event loop.

Another example illustrates why the problem is occurring. Even though you take the layout item, the underlying widget is still parented to the original layouts widget.

def deleteButton():     b = layout.takeAt(2)     buttons.pop(2)     w = b.widget()     w.setParent(None) 

This is not the preferred way, as it still leaves the cleanup of the object ambiguous. But it shows that clearing the parent allows it to leave the visual display. Use deleteLater() though. It properly cleans everything up.

like image 106
jdi Avatar answered Sep 18 '22 08:09

jdi