2012-03-28 251 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