如何删除小部件

How to delete widgets

发布的代码创建了一个包含 5 行小部件的 window。 单击 Push Button 会启动 btnClicked 函数,该函数无法使用 .takeAt() 方法从所有小部件中清除 window。为什么?

from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])

view = QtGui.QWidget() 
view.setLayout(QtGui.QVBoxLayout())

def btnClicked():
    items = []
    for i in range( view.layout().count() ):
        item = view.layout().itemAt(i)
        items.append(item)

    for num, item in enumerate(items):
        print 'taking out item:', num, item 
        view.layout().takeAt(num)


for i in range(5):
    sublayout = QtGui.QHBoxLayout()
    view.layout().addLayout(sublayout)

    sublayout.addWidget(QtGui.QLabel('Label:'))
    sublayout.addWidget(QtGui.QLineEdit('Text Edit'))

    btn = QtGui.QPushButton('Push Button')
    btn.clicked.connect(btnClicked)
    sublayout.addWidget(btn)

view.show()
app.exec_()

首先,您无法在遍历容器时安全地从容器中移除项目。每次你从布局中取出一个项目,剩下的项目都会向下移动,它们的索引也会相应地改变。因此,一旦超过 half-way 点,您的循环计数器将不再引用有效项目。在循环中删除项目的正确方法是这样的:

def btnClicked():
     layout = view.layout()
     while layout.count():
         item = layout.takeAt(0)
         print(repr(item))

其次,您要删除的布局项目是 layout-items,而不是小部件。删除所有布局后,所有小部件都将保留在原处。如果您使用上面的方法,然后调整 window 的大小,您可以看到这一点 - 小部件不再由任何布局管理,因此它们也不会调整大小。

将小部件添加到布局后,它们会自动 re-parented 到拥有该布局的小部件。如果删除该父窗口小部件,则其所有子窗口小部件也将被递归删除。因此,必须明确删除小部件(或其父级)才能将其完全删除:

def clearLayout(layout):
    if layout is not None:
        while layout.count():
            item = layout.takeAt(0)
            widget = item.widget()
            if widget is not None:
                widget.deleteLater()
            else:
                clearLayout(item.layout())

def btnClicked():
     clearLayout(view.layout())