Подтвердить что ты не робот

PySide: удаление виджета из макета

Я пытаюсь удалить виджет Qt из макета в приложении PySide.

Вот минимальный пример. Это виджет с 5 кнопками в нем, и средний должен удалить себя при нажатии:

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

Кнопка нечеткая и явно не учитывается при расчетах компоновки, но ее изображение остается на месте.

Согласно документации Qt, правильный способ удаления всех объектов из макета:

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

Здесь я просто хочу удалить третью кнопку, поэтому я просто вызываю takeAt(2), а затем del b, чтобы вызвать деструктор на этом элементе. Объект кнопки также находится в .pop 'd из списка buttons, чтобы убедиться, что ссылка на объект отсутствует. Как мой код отличается от кода в документах Qt, который может вызвать такое поведение?

4b9b3361

Ответ 1

Супер простое исправление:

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

Сначала вам нужно убедиться, что вы обращаетесь к фактической кнопке, а не к QWidgetItem, которая возвращается из макета, а затем вызывайте deleteLater(), которая сообщит Qt об уничтожении виджета после окончания этого слота и управления возвращается к событию петля.

Другой пример иллюстрирует, почему возникает проблема. Несмотря на то, что вы берете элемент макета, базовый виджет по-прежнему зависит от исходного виджета макетов.

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

Это не самый предпочтительный способ, так как он по-прежнему оставляет очистку объекта неоднозначным. Но это показывает, что очистка родителя позволяет ему покинуть визуальный дисплей. Используйте deleteLater(). Он правильно очищает все.