65 votes

Effacer tous les widgets dans une disposition dans pyqt

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 de l'application plot_layout ? Je ne vois pas de méthode de ce type.

136voto

PALEN Points 1710

Après de nombreuses recherches (et celle-ci m'a pris pas mal de temps, donc je l'ajoute ici pour référence future), voici la méthode que j'ai trouvée pour vraiment éclaircir et supprimer les widgets dans une disposition :

for i in reversed(range(layout.count())): 
    layout.itemAt(i).widget().setParent(None)

Ce que la documentation dit à propos du QWidget c'est que :

Le nouveau widget est supprimé lorsque son parent est supprimé.

Remarque importante : Vous devez effectuer une boucle en arrière car la suppression des éléments du début déplace les éléments et modifie l'ordre des éléments dans la mise en page.

Pour tester et confirmer que la mise en page 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 comporte toujours des éléments, contrairement au code avec setParent .

42voto

Nadeem Douba Points 61

C'est 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 de Qt http://doc.qt.io/qt-5/qlayout.html#takeAt . N'oubliez pas que lorsque vous supprimez des enfants du modèle dans une boucle while ou for, vous modifiez effectivement l'indice # de chaque élément enfant du modèle. C'est la raison pour laquelle vous rencontrerez des problèmes si vous utilisez une balise for i in range() boucle.

1 votes

Je suppose que vous voulez dire child.widget().deleteLater()... Merci beaucoup pour cela - cela semble être une solution assez élégante. Si deleteLater() me pose problème, je peux essayer close() ou setParent(None) comme d'autres l'ont suggéré.

30voto

Blaa_Thor Points 157

La réponse de PALEN fonctionne bien si vous n'avez pas besoin d'ajouter de nouveaux widgets à votre mise en page.

for i in reversed(range(layout.count())): 
    layout.itemAt(i).widget().setParent(None)

Mais vous obtiendrez un "Segmentation fault (core dumped)" à un moment donné si vous videz et remplissez le layout plusieurs fois ou avec de nombreux widgets. Il semble que le layout conserve une liste de widgets et que cette liste soit limitée en taille.

Si vous retirez 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.

1 votes

Merci beaucoup, cela me rendait fou de voir que j'obtenais "Process finished with exit code 139" après avoir effacé et ajouté des éléments plusieurs fois.

2 votes

setParent(None) ne supprime pas les widgets. Voir mes commentaires et réponses sur la réponse de Palens. C'est également la raison de la Segmentation fault . Utilisez deleteLater() à la place.

0 votes

python widget.setAttribute(QtCore.Qt.WA_DeleteOnClose) widget.close() gridLayout.removeWidget(widget) Il fonctionne parfaitement pour moi

20voto

user3369214 Points 351

C'est comme ça que je nettoie une mise en page :

def clearLayout(layout):
    if layout is not 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())

14voto

mindinpanic Points 135

Vous pouvez utiliser le close() méthode de widget :

for i in range(layout.count()): layout.itemAt(i).widget().close()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X