2012-03-28 8 views
17

Я пытаюсь удалить виджет Qt из макета в приложении PySide.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

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

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

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

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

+5

Я просто хочу поздравить вас с действительно хорошо сформированным вопросом. В последнее время я так много вижу, это всего лишь несколько предложений без контекста или массивный код, который мы, как ожидается, будем читать. У этого есть очень ясная проблема, заявленная, наряду с чрезвычайно кратким и управляемым примером кода. Ваши фотографии еще более проясняют проблему. И вы показываете, что вы пробовали. Браво! – jdi

ответ

28

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

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(). Он правильно очищает все.

+0

Отлично, спасибо ~ Мои волосы также благодаря вам, потому что больше не тянут. –

+0

Hah. Да, я тоже это понял, когда впервые начал работать с макетами, в которых дети приходили и уходили. – jdi

+7

Просто добавьте очень хороший ответ: 'Q * Макет' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ' Они просто выступают в качестве агента передачи родительства. Даже если вы удалите виджет из макета, виджет контейнера по-прежнему остается в качестве родителя, и ваша кнопка все еще существует. – Avaris