Python 清除pyqt中布局中的所有小部件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4528347/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 16:08:51  来源:igfitidea点击:

Clear all widgets in a layout in pyqt

pythonqtpyqtpyqt4

提问by Falmarri

Is there a way to clear (delete) all the widgets in a layout?

有没有办法清除(删除)布局中的所有小部件?

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

Now I want to replace the widget in plot_layoutwith a new widget. Is there an easy way to clear all the widgets in plot_layout? I don't see any method such.

现在我想plot_layout用一个新的小部件替换小部件。有没有一种简单的方法可以清除 中的所有小部件plot_layout?我没有看到任何这样的方法。

采纳答案by PALEN

After a lot of research (and this one took quite time, so I add it here for future reference), this is the way I found to really clear and deletethe widgets in a layout:

经过大量研究(这个研究花了很长时间,所以我在这里添加以供将来参考),这是我发现真正清除和删除布局中的小部件的方法:

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

What the documentation says about the QWidgetis that:

关于QWidget的文档说的是:

The new widget is deleted when its parent is deleted.

删除其父级时,新小部件也将被删除。

Important note:You need to loop backwards because removing things from the beginning shifts items and changes the order of items in the layout.

重要说明:您需要向后循环,因为从开头删除内容会移动项目并更改布局中项目的顺序。

To test and confirm that the layout is empty:

要测试并确认布局为空:

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


There seems to be another way to do it. Instead of using the setParent function, use the deleteLater()function like this:

似乎还有另一种方法可以做到。不使用 setParent 函数,而是使用deleteLater()函数,如下所示:

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

The documentation says that QObject.deleteLater (self)

文档说QObject.deleteLater (self)

Schedules this object for deletion.

计划删除此对象。

However, if you run the test code specified above, it prints some values. This indicates that the layout still has items, as opposed to the code with setParent.

但是,如果您运行上面指定的测试代码,它会打印一些值。这表明布局仍然有项目,而不是带有setParent的代码。

回答by Falmarri

From the docs:

从文档:

To remove a widget from a layout, call removeWidget(). Calling QWidget.hide()on a widget also effectively removes the widget from the layout until QWidget.show()is called.

要从布局中删除小部件,请调用removeWidget()。调用QWidget.hide()小部件也会有效地从布局中删除小部件,直到QWidget.show()被调用。

removeWidgetis inherited from QLayout, that's why it's not listed among the QGridLayoutmethods.

removeWidget继承自QLayout,这就是为什么它没有列在QGridLayout方法中的原因。

回答by Harald Scheirich

A couple of solutions, if you are swapping between known views using a stacked widget and just flipping the shown index might be a lot easier than adding and removing single widgets from a layout.

几个解决方案,如果您使用堆叠小部件在已知视图之间交换并且仅翻转显示的索引可能比从布局中添加和删除单个小部件容易得多。

If you want to replace allthe children of a widget then the QObjectfunctions findChildrenshould get you there e.g. I don't know how the template functions are wrapped in pyqt though. But you could also search for the widgets by name if you know them.

如果你想替换一个小部件的所有子项,那么QObject函数findChildren应该会让你到达那里,例如我不知道模板函数是如何包装在 pyqt 中的。但是,如果您知道这些小部件,您也可以按名称搜索它们。

回答by joshua

My solution to this problem is to override the setLayout method of QWidget. The following code updates the layout to the new layout which may or may not contain items that are already displayed. You can simply create a new layout object, add whatever you want to it, then call setLayout. Of course, you can also just call clearLayout to remove everything.

我对这个问题的解决方法是重写QWidget的setLayout方法。以下代码将布局更新为新布局,该布局可能包含也可能不包含已显示的项目。你可以简单地创建一个新的布局对象,添加任何你想要的东西,然后调用 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)

回答by Volodymyr Pavlenko

You can use the close()method of widget:

您可以使用以下close()方法widget

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

回答by Nadeem Douba

This may be a bit too late but just wanted to add this for future reference:

这可能有点晚了,但只是想添加它以供将来参考:

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

Adapted from Qt docs http://doc.qt.io/qt-5/qlayout.html#takeAt. Remember that when you are removing children from the layout in a while or for loop, you are effectively modifying the index # of each child item in the layout. That's why you'll run into problems using a for i in range()loop.

改编自 Qt 文档http://doc.qt.io/qt-5/qlayout.html#takeAt。请记住,当您在 while 或 for 循环中从布局中删除子项时,您实际上是在修改布局中每个子项的索引号。这就是使用for i in range()循环时会遇到问题的原因。

回答by borovsky

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

or

或者

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

回答by user3369214

That's how I clear a layout :

这就是我清除布局的方式:

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

回答by Blaa_Thor

The answer from PALEN works well if you do not need to put new widgets to your layout.

如果您不需要在布局中放置新的小部件,那么 PALEN 的答案会很有效。

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

But you will get a "Segmentation fault (core dumped)" at some point if you empty and fill the layout many times or with many widgets. It seems that the layout keeps a list of widget and that this list is limited in size.

但是,如果您多次清空并填充布局或使用许多小部件,您将在某些时候收到“分段错误(核心转储)”。布局似乎保留了一个小部件列表,并且该列表的大小有限。

If you remove the widgets that way:

如果您以这种方式删除小部件:

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)

You won't get that problem.

你不会遇到那个问题。

回答by SoloPilot

I use:

我用:

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