Очистить все виджеты в макете в Pyqt - PullRequest
37 голосов
/ 25 декабря 2010

Есть ли способ очистки (удаления) всех виджетов в макете?

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

Теперь я хочу заменить виджет в plot_layout новым виджетом.Есть ли простой способ очистить все виджеты в plot_layout?Я не вижу такого способа.

Ответы [ 11 ]

65 голосов
/ 27 октября 2012

После долгих исследований (и это заняло довольно много времени, поэтому я добавил его сюда для дальнейшего использования), я нашел способ действительно очистить и удалить виджеты в макете:

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

В документации говорится о QWidget :

Новый виджет удаляется при удалении его родителя.

Важное примечание: Необходимо выполнить цикл в обратном направлении, поскольку при удалении объектов с начала элементы перемещаются и изменяется порядок элементов в макете.

Для проверки иубедитесь, что макет пуст:

for i in range(layout.count()): print i

Кажется, есть другой способ сделать это.Вместо использования функции setParent используйте функцию deleteLater () , например:

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

В документации сказано, что QObject.deleteLater (self)

Запланирует удаление этого объекта.

Однако, если вы запустите тестовый код, указанный выше, он напечатает некоторые значения.Это означает, что в макете по-прежнему есть элементы, в отличие от кода с setParent .

22 голосов
/ 09 апреля 2012

Это может быть слишком поздно, но я просто хотел добавить это для дальнейшего использования:

def clearLayout(layout):
  while layout.count():
    child = layout.takeAt(0)
    if child.widget():
      child.widget().deleteLater()

Адаптировано из Qt docs http://doc.qt.io/qt-5/qlayout.html#takeAt. Помните, что при удалении дочерних элементов из макетачерез цикл while или for вы эффективно модифицируете индекс # каждого дочернего элемента в макете.Вот почему вы столкнетесь с проблемами при использовании цикла for i in range().

17 голосов
/ 15 августа 2014

Ответ от PALEN работает хорошо, если вам не нужно добавлять новые виджеты в ваш макет.

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

Но в какой-то момент вы получите «Ошибка сегментации (сброшено ядро)», если вы очистите и заполните макет много раз или со многими виджетами. Кажется, что макет хранит список виджетов и что этот список ограничен в размере.

Если вы удалите виджеты таким образом:

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)

У тебя не будет этой проблемы.

10 голосов
/ 15 апреля 2014

Вот так я очищаю макет:

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 голосов
/ 28 ноября 2011

Вы можете использовать close() метод widget:

for i in range(layout.count()): layout.itemAt(i).widget().close()
3 голосов
/ 19 апреля 2011

Мое решение этой проблемы - переопределить метод setLayout QWidget. Следующий код обновляет макет до нового макета, который может содержать или не содержать элементы, которые уже отображаются. Вы можете просто создать новый объект макета, добавить к нему все, что хотите, а затем вызвать setLayout Конечно, вы также можете просто вызвать clearLayout, чтобы удалить все.

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)
2 голосов
/ 08 октября 2014

Я использую:

    while layout.count() > 0: 
        layout.itemAt(0).setParent(None)
2 голосов
/ 25 декабря 2010

Из документов:

Чтобы удалить виджет из макета, вызовите removeWidget().Вызов QWidget.hide() для виджета также эффективно удаляет виджет из макета до тех пор, пока не будет вызван QWidget.show().

removeWidget наследуется от QLayout, поэтому его нет в списке QGridLayout методы.

1 голос
/ 05 августа 2018

я впервые отвечаю на вопрос о переполнении стека, но я вижу, что все ответы здесь немного неправильные.(да, я знаю, что вопрос заключался в том, чтобы удалить все виджеты) Проблема с большинством из них заключается в том, что они не учитывают вложенные макеты, поэтому я сделал рекурсивную функцию, которая с учетом макета будет рекурсивно удалять все внутри негои все макеты внутри него.вот оно:

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)

Возможно, я не учел все типы пользовательского интерфейса, не уверен.Надеюсь, это поможет!

1 голос
/ 25 декабря 2010

Пара решений, если вы переключаетесь между известными представлениями с помощью сложенного виджета и просто перелистываете показанный индекс, может быть намного проще, чем добавлять и удалять отдельные виджеты из макета.

Если вы хотите заменить всех дочерних элементов виджета, то QObject функции findChildren должны привести вас туда, например. Я не знаю, как функции шаблона заключены в pyqt. Но вы также можете искать виджеты по имени, если вы их знаете.

...