web-dev-qa-db-fra.com

Effacer tous les widgets d'une présentation 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 dans plot_layout? Je ne vois aucune méthode de ce genre.

37
Falmarri

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 .

68
PALEN

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().

22
Nadeem Douba

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.

17
Blaa_Thor

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

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

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())
10
user3369214

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)
3
joshua

De la documentation:

Pour supprimer un widget d'une mise en page, appelez removeWidget(). L'appel de QWidget.hide() sur un widget supprime également le widget de la mise en page jusqu'à ce que QWidget.show() soit appelé.

removeWidget est hérité de QLayout, c'est pourquoi il n'est pas répertorié parmi les méthodes QGridLayout.

2
user395760

J'utilise:

    while layout.count() > 0: 
        layout.itemAt(0).setParent(None)
2
SoloPilot

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!

1
Arthur Fakhreddine

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 QObjectfindChildren 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.

1
Harald Scheirich
        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)
0
borovsky