python - tutorial - Borrar todos los widgets en un diseño en pyqt
pyqt tutorial (11)
Así es como elimino un diseño:
def clearLayout(layout):
if layout != None:
while layout.count():
child = layout.takeAt(0)
if child.widget() is not None:
child.widget().deleteLater()
elif child.layout() is not None:
clearLayout(child.layout())
¿Hay alguna manera de borrar (eliminar) todos los widgets en un diseño?
self.plot_layout = QtGui.QGridLayout()
self.plot_layout.setGeometry(QtCore.QRect(200,200,200,200))
self.root_layout.addLayout(self.plot_layout)
self.plot_layout.addWidget(MyWidget())
Ahora quiero reemplazar el widget en plot_layout
con un nuevo widget. ¿Hay alguna manera fácil de borrar todos los widgets en plot_layout
? No veo ningún método como ese.
De los documentos:
Para eliminar un widget de un diseño, llame a
removeWidget()
. Llamar aQWidget.hide()
en un widget también elimina efectivamente el widget del diseño hasta que seQWidget.show()
.
removeWidget
se hereda de QLayout
, es por eso que no aparece entre los métodos de QGridLayout
.
Después de una gran cantidad de investigaciones (y esta tomó bastante tiempo, así que lo agregué aquí para referencia futura), esta es la forma en que descubrí realmente borrar y eliminar los widgets en un diseño:
for i in reversed(range(layout.count())):
layout.itemAt(i).widget().setParent(None)
Lo que dice la documentación sobre QWidget es que:
El nuevo widget se elimina cuando se elimina su padre.
Nota importante: debe retroceder porque la eliminación de elementos desde el principio cambia los elementos y cambia el orden de los elementos en el diseño.
Para probar y confirmar que el diseño está vacío:
for i in range(layout.count()): print i
Parece que hay otra forma de hacerlo. En lugar de usar la función setParent, use la función deleteLater() como esta:
for i in reversed(range(layout.count())):
layout.itemAt(i).widget().deleteLater()
La documentación dice que QObject.deleteLater (self)
Programa este objeto para su eliminación.
Sin embargo, si ejecuta el código de prueba especificado anteriormente, imprime algunos valores. Esto indica que el diseño todavía tiene elementos, a diferencia del código con setParent .
Esto puede ser un poco tarde pero solo quería agregar esto para futuras referencias:
def clearLayout(layout):
while layout.count():
child = layout.takeAt(0)
if child.widget():
child.widget().deleteLater()
Adaptado de Qt docs http://doc.qt.io/qt-5/qlayout.html#takeAt . Recuerde que cuando está eliminando elementos secundarios del diseño por un tiempo o por un bucle, está modificando efectivamente el índice # de cada elemento secundario en el diseño. Es por eso que te encontrarás con problemas al utilizar un bucle for i in range()
.
La respuesta de PALEN funciona bien si no necesita instalar nuevos widgets en su diseño.
for i in reversed(range(layout.count())):
layout.itemAt(i).widget().setParent(None)
Pero obtendrá un "Error de segmentación (núcleo volcado)" en algún momento si vacía y llena el diseño muchas veces o con muchos widgets. Parece que el diseño mantiene una lista de widgets y que esta lista tiene un tamaño limitado.
Si elimina los widgets de esa manera:
for i in reversed(range(layout.count())):
widgetToRemove = layout.itemAt( i ).widget()
# remove it from the layout list
layout.removeWidget( widgetToRemove )
# remove it from the gui
widgetToRemove.setParent( None )
No tendrás ese problema.
Mi solución a este problema es anular el método setLayout de QWidget. El siguiente código actualiza el diseño del nuevo diseño, que puede contener o no elementos que ya se muestran. Simplemente puede crear un nuevo objeto de diseño, agregar lo que quiera y luego llamar a setLayout. Por supuesto, también puedes llamar a clearLayout para eliminar todo.
def setLayout(self, layout):
self.clearLayout()
QWidget.setLayout(self, layout)
def clearLayout(self):
if self.layout() is not None:
old_layout = self.layout()
for i in reversed(range(old_layout.count())):
old_layout.itemAt(i).widget().setParent(None)
import sip
sip.delete(old_layout)
Puede usar el método de widget
close()
:
for i in range(layout.count()): layout.itemAt(i).widget().close()
Un par de soluciones, si está intercambiando entre vistas conocidas usando un widget apilado y solo volteando el índice mostrado, puede ser mucho más fácil que agregar y eliminar widgets individuales de un diseño.
Si desea reemplazar todos los elementos findChildren
de un widget, entonces las funciones de QObject
findChildren
deberían findChildren
allí. No findChildren
, no sé cómo se envuelven las funciones de la plantilla en pyqt. Pero también puedes buscar los widgets por nombre si los conoces.
Yo suelo:
while layout.count() > 0:
layout.itemAt(0).setParent(None)
esta es la primera vez que contesto una pregunta de desbordamiento de pila, pero veo que todas las respuestas aquí son un poco erróneas. (sí, sé que la pregunta era para eliminar todos los widgets). El problema con la mayoría de ellos es que no tienen en cuenta los diseños anidados, así que hice una función recursiva, que dado un diseño eliminará todo dentro de ella recursivamente, y todos los diseños dentro de ella. aquí está:
def clearLayout(layout):
print("-- -- input layout: "+str(layout))
for i in reversed(range(layout.count())):
layoutItem = layout.itemAt(i)
if layoutItem.widget() is not None:
widgetToRemove = layoutItem.widget()
print("found widget: " + str(widgetToRemove))
widgetToRemove.setParent(None)
layout.removeWidget(widgetToRemove)
elif layoutItem.spacerItem() is not None:
print("found spacer: " + str(layoutItem.spacerItem()))
else:
layoutToRemove = layout.itemAt(i)
print("-- found Layout: "+str(layoutToRemove))
clearLayout(layoutToRemove)
Puede que no haya contabilizado todos los tipos de IU, no estoy seguro. ¡Espero que esto ayude!
for i in reversed (range(layout.count())):
layout.itemAt(i).widget().close()
layout.takeAt(i)
o
for i in range(layout.count()):
layout.itemAt(0).widget().close()
layout.takeAt(0)