Existe-t-il un moyen d'effacer (supprimer) tous les widgets d'une mise en page?
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())
Maintenant, je veux remplacer le widget dans plot_layout
avec un nouveau widget. Existe-t-il un moyen simple d'effacer tous les widgets dans plot_layout
? Je ne vois aucune méthode de ce genre.
Après beaucoup de recherches (et celle-ci a pris du temps, je l'ajoute ici pour référence future), c'est la façon dont j'ai trouvé vraiment clair et supprimé les widgets dans une mise en page:
for i in reversed(range(layout.count())):
layout.itemAt(i).widget().setParent(None)
Ce que la documentation dit sur le QWidget est que:
Le nouveau widget est supprimé lorsque son parent est supprimé.
Remarque importante: Vous devez effectuer une boucle vers l'arrière car la suppression des éléments depuis le début modifie les éléments et modifie l'ordre des éléments dans la mise en page.
Pour tester et confirmer que la présentation est vide:
for i in range(layout.count()): print i
Il semble y avoir une autre façon de procéder. Au lieu d'utiliser la fonction setParent, utilisez la fonction deleteLater () comme ceci:
for i in reversed(range(layout.count())):
layout.itemAt(i).widget().deleteLater()
La documentation indique que QObject.deleteLater (self)
Planifie la suppression de cet objet.
Cependant, si vous exécutez le code de test spécifié ci-dessus, il imprime certaines valeurs. Cela indique que la mise en page contient toujours des éléments, contrairement au code avec setParent .
Cela peut être un peu trop tard, mais je voulais juste ajouter ceci pour référence future:
def clearLayout(layout):
while layout.count():
child = layout.takeAt(0)
if child.widget():
child.widget().deleteLater()
Adapté de la documentation Qt http://doc.qt.io/qt-5/qlayout.html#takeAt . N'oubliez pas que lorsque vous supprimez des enfants de la disposition dans une boucle while ou for, vous modifiez effectivement l'index # de chaque élément enfant de la disposition. C'est pourquoi vous rencontrerez des problèmes en utilisant une boucle for i in range()
.
La réponse de PALEN fonctionne bien si vous n'avez pas besoin de mettre de nouveaux widgets dans votre mise en page.
for i in reversed(range(layout.count())):
layout.itemAt(i).widget().setParent(None)
Mais vous obtiendrez un "défaut de segmentation (core dumped)" à un moment donné si vous videz et remplissez la disposition plusieurs fois ou avec de nombreux widgets. Il semble que la mise en page conserve une liste de widgets et que cette liste soit limitée en taille.
Si vous supprimez les widgets de cette façon:
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)
Vous n'aurez pas ce problème.
Vous pouvez utiliser la méthode close()
de widget
:
for i in range(layout.count()): layout.itemAt(i).widget().close()
Voilà comment j'efface une mise en page:
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())
Ma solution à ce problème consiste à remplacer la méthode setLayout de QWidget. Le code suivant met à jour la disposition vers la nouvelle disposition qui peut ou non contenir des éléments déjà affichés. Vous pouvez simplement créer un nouvel objet de disposition, y ajouter ce que vous voulez, puis appeler setLayout. Bien sûr, vous pouvez également simplement appeler clearLayout pour tout supprimer.
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)
De la documentation:
Pour supprimer un widget d'une mise en page, appelez
removeWidget()
. L'appel deQWidget.hide()
sur un widget supprime également le widget de la mise en page jusqu'à ce queQWidget.show()
soit appelé.
removeWidget
est hérité de QLayout
, c'est pourquoi il n'est pas répertorié parmi les méthodes QGridLayout
.
J'utilise:
while layout.count() > 0:
layout.itemAt(0).setParent(None)
c'est la première fois que je réponds à une question de débordement de pile, mais j'ai vu que toutes les réponses ici sont légèrement fausses. (oui, je sais que la question était de supprimer tous les widgets) Le problème avec la plupart d'entre eux est qu'ils ne tiennent pas compte des dispositions imbriquées, j'ai donc fait une fonction récursive, qui, étant donné une disposition, supprimera récursivement tout ce qu'il contient, et toutes les dispositions à l'intérieur. C'est ici:
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)
Je n'ai peut-être pas pris en compte tous les types d'interface utilisateur, je n'en suis pas sûr. J'espère que cela t'aides!
Quelques solutions, si vous permutez entre des vues connues en utilisant un widget empilé et en retournant simplement l'index affiché peut être beaucoup plus facile que d'ajouter et de supprimer des widgets uniques d'une mise en page.
Si vous souhaitez remplacer tous les enfants d'un widget, les fonctions QObject
findChildren
devraient vous y conduire, par exemple Je ne sais pas comment les fonctions du modèle sont enveloppées dans pyqt. Mais vous pouvez également rechercher les widgets par nom si vous les connaissez.
for i in reversed (range(layout.count())):
layout.itemAt(i).widget().close()
layout.takeAt(i)
ou
for i in range(layout.count()):
layout.itemAt(0).widget().close()
layout.takeAt(0)