2012-03-28 256 views
17

我试图从PySide应用程序中的布局中删除Qt小部件。PySide:从布局中删除小部件

这是一个简单的例子。这是与它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_() 

实际发生的是:

What actually happens

按钮是不可点击,并明确没有考虑到布局计算,但其图像保持原位。

按照Qt documentation,从布局删除所有对象的正确的方法是:

while ((child = layout->takeAt(0)) != 0) { 
    delete child; 
} 

在这里,我只是想删除的第三个按钮,所以我就打电话takeAt(2),然后del b调用该项目的析构函数。按钮对象也是buttons列表中的.pop'd,以确保不存在对该对象的剩余引用。我的代码与Qt文档中的代码有什么不同,会导致这种行为?

+5

我只想在一个非常合适的问题上恭喜你。我最近看到很多这样的东西,只是几句没有上下文的句子,或者是我们期望阅读的大量代码。这有一个非常明确的问题,以及一个非常简洁和可运行的代码示例。你的照片还可以进一步澄清这个问题。并且你展示你的尝试。好样的! – jdi 2012-03-28 00:19:53

回答

28

超级简单的解决方法:

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()。它正确地清理了一切。

+0

完美,谢谢〜我的头发也感谢你,因为它不再被拉动。 – 2012-03-28 00:21:40

+0

哈。当我第一次开始使用有孩子来来往往的布局时,我也受到了这一点。 – jdi 2012-03-28 00:26:15

+7

只需添加一个很好的答案:'Q *布局'从不是一个部件的'父',因为一个部件的父部件必须是另一个部件,'Q *布局'不是从'QWidget'派生的。他们只是充当父母的转移代理人。即使您从布局中移除小部件,容器小部件仍将保留为父级,并且您的按钮仍然存在。 – Avaris 2012-03-28 00:32:13