25

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_()

実際に起こることはこれです:

実際に何が起こるか

ボタンはクリックできず、レイアウトの計算では明らかに考慮されませんが、画像はそのまま残ります。

Qtのドキュメントによると、レイアウトからすべてのオブジェクトを削除する正しい方法は次のとおりです。

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

ここでは、3番目のボタンを削除したいので、takeAt(2)del b呼び出してから、そのアイテムのデストラクタを呼び出します。ボタンオブジェクトもリスト.popからbuttons削除され、オブジェクトへの参照が残っていないことを確認します。私のコードは、そのような動作を引き起こすQtドキュメントのコードとどのように異なりますか?

4

2 に答える 2

42

超簡単な修正:

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()。それはすべてを適切にクリーンアップします。

于 2012-03-28T00:11:53.300 に答える