有没有办法清除(删除)布局中的所有小部件?
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
中的所有小部件?我没有看到任何这样的方法。
答案 0 :(得分:65)
经过大量的研究(这个花了很长时间,所以我在这里添加它以供将来参考),这是我发现在布局中真正清除和删除小部件的方式:
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 的代码。
答案 1 :(得分:22)
这可能有点太晚了,但只是想添加它以供将来参考:
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()
循环的问题。
答案 2 :(得分:16)
如果您不需要在布局中添加新的小部件,PALEN的答案效果很好。
for i in reversed(range(layout.count())):
layout.itemAt(i).widget().setParent(None)
但是你会得到一个" Segmentation fault(core dumped)"在某些时候,如果你清空并多次填充布局或使用许多小部件。似乎布局保留了一个小部件列表,并且该列表的大小有限。
如果您以这种方式删除小部件:
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)
你不会遇到这个问题。
答案 3 :(得分:10)
您可以使用close()
的{{1}}方法:
widget
答案 4 :(得分:10)
这就是我清除布局的方式:
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())
答案 5 :(得分:3)
我对此问题的解决方法是覆盖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)
答案 6 :(得分:2)
来自文档:
要从布局中删除小部件,请致电
removeWidget()
。在窗口小部件上调用QWidget.hide()
也可以有效地从布局中删除窗口小部件,直到调用QWidget.show()
。
removeWidget
继承自QLayout
,这就是为什么它没有列在QGridLayout
方法中。
答案 7 :(得分:2)
我用:
while layout.count() > 0:
layout.itemAt(0).setParent(None)
答案 8 :(得分:2)
这是我第一次真正回答堆栈溢出问题,但是我看到这里的所有答案都略有错误。 (是的,我知道问题是要删除所有小部件)大多数问题是它们没有考虑嵌套的布局,因此我做了一个递归函数,给定一个布局,它将以递归方式删除其中的所有内容,以及其中的所有布局。在这里:
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)
不确定,我可能没有考虑所有的UI类型。希望这会有所帮助!
答案 9 :(得分:1)
一些解决方案,如果您使用堆叠小部件在已知视图之间进行交换,只是翻转显示的索引可能比从布局中添加和删除单个小部件容易得多。
如果您想要替换所有小部件的子项,那么QObject
函数findChildren
可以帮助您我不知道模板函数是如何包装在pyqt中的。但是如果你知道它们,你也可以按名称搜索小部件。
答案 10 :(得分:0)
for i in reversed (range(layout.count())):
layout.itemAt(i).widget().close()
layout.takeAt(i)
或
for i in range(layout.count()):
layout.itemAt(0).widget().close()
layout.takeAt(0)
答案 11 :(得分:0)
我遇到了前面提到的解决方案的问题。存在导致问题的挥之不去的小部件;我怀疑已安排删除,但未完成。我还必须将小部件父级设置为无。 这是我的解决方案:
def clearLayout(layout):
while layout.count():
child = layout.takeAt(0)
childWidget = child.widget()
if childWidget:
childWidget.setParent(None)
childWidget.deleteLater()