Python PySide:从布局中删除小部件

Python PySide:从布局中删除小部件,python,qt,pyside,qlayout,Python,Qt,Pyside,Qlayout,我正在尝试从PySide应用程序的布局中删除Qt小部件 这里是一个最小的例子。这是一个有5个按钮的小部件,中间的按钮应该在单击时自动删除: import sys from PySide import QtGui app = QtGui.QApplication(sys.argv) widget = QtGui.QWidget() layout = QtGui.QVBoxLayout() buttons = [QtGui.QPushButton(str(x)) for x in xrange(5

我正在尝试从PySide应用程序的布局中删除Qt小部件

这里是一个最小的例子。这是一个有5个按钮的小部件,中间的按钮应该在单击时自动删除:

import sys
from PySide import QtGui

app = QtGui.QApplication(sys.argv)
widget = QtGui.QWidget()
layout = QtGui.QVBoxLayout()
buttons = [QtGui.QPushButton(str(x)) for x in xrange(5)]

def deleteButton():
    b = layout.takeAt(2)
    buttons.pop(2)
    del b
buttons[2].clicked.connect(deleteButton)

map(layout.addWidget, buttons)
widget.setLayout(layout)
widget.show()
app.exec_()
实际情况是:

按钮是不可点击的,显然在布局计算中没有考虑到,但其图像保持不变

根据,从布局中删除所有对象的正确方法是:

while ((child = layout->takeAt(0)) != 0) {
    delete child;
}
这里我只想删除第三个按钮,所以我只需调用
takeAt(2)
,然后
delb
调用该项的析构函数。按钮对象也是从按钮列表中弹出的,以确保没有对对象的剩余引用。我的代码与Qt文档中可能导致这种行为的代码有何不同?

超级简单修复:

def deleteButton():
    b = layout.takeAt(2)
    buttons.pop(2)
    b.widget().deleteLater()
您首先必须确保寻址的是实际的按钮,而不是从布局返回的QWidgetItem,然后调用deleteLater(),这将告诉Qt在该插槽结束后销毁小部件,并将控件返回到事件循环

另一个例子说明了问题发生的原因。即使您使用布局项,底层小部件仍然是原始布局小部件的父级

def deleteButton():
    b = layout.takeAt(2)
    buttons.pop(2)
    w = b.widget()
    w.setParent(None)

这不是首选方法,因为它仍然使对象的清理不明确。但它表明,清除父项允许它离开可视显示。不过,请使用
deleteLater()
。它能很好地清理一切。

我只想祝贺你提出了一个非常有条理的问题。我最近看到了很多,只是一些没有上下文的句子,或者是我们期望阅读的大量代码。这说明了一个非常明确的问题,以及一个非常简洁且可运行的代码示例。你的照片也进一步澄清了这个问题。你要展示你所尝试过的。好极了!太好了,谢谢~我的头发也谢谢你,因为它不再被扯了。哈。是的,当我第一次开始处理有孩子来来去去去的布局时,我也被这一点咬了一口。我要补充一个非常好的答案:
Q*Layout
s从来都不是小部件的父项,因为小部件的父项必须是另一个小部件,
Q*Layout
不是从
QWidget
派生出来的。他们只是作为父母身份的转移代理。即使您从布局中删除了小部件,容器小部件仍然是父部件,并且您的按钮仍然存在。