web-dev-qa-db-ja.com

pyqtのレイアウト内のすべてのウィジェットをクリアします

レイアウト内のすべてのウィジェットをクリア(削除)する方法はありますか?

self.plot_layout = QtGui.QGridLayout()
self.plot_layout.setGeometry(QtCore.QRect(200,200,200,200))
self.root_layout.addLayout(self.plot_layout)
self.plot_layout.addWidget(MyWidget())

次に、plot_layoutのウィジェットを新しいウィジェットに置き換えます。 plot_layoutのすべてのウィジェットをクリアする簡単な方法はありますか?そのような方法は見当たりません。

37
Falmarri

多くの研究の後(そしてこれはかなり時間がかかったので、今後の参照のためにここに追加します)、これは本当に明確であることがわかった方法ですdeleteレイアウト内のウィジェット:

for i in reversed(range(layout.count())): 
    layout.itemAt(i).widget().setParent(None)

QWidgetについてのドキュメントの記述は次のとおりです。

新しいウィジェットは、その親が削除されると削除されます。

重要な注意:アイテムを最初から削除するとアイテムが移動し、レイアウト内のアイテムの順序が変わるため、逆方向にループする必要があります。

レイアウトが空であることをテストして確認するには:

for i in range(layout.count()): print i

別の方法があるようです。 setParent関数を使用する代わりに、次のように deleteLater() 関数を使用します。

for i in reversed(range(layout.count())): 
    layout.itemAt(i).widget().deleteLater()

ドキュメントには、QObject.deleteLater(self)

このオブジェクトの削除をスケジュールします。

ただし、上記で指定したテストコードを実行すると、いくつかの値が出力されます。これは、setParentを使用したコードとは対照的に、レイアウトにまだアイテムがあることを示しています。

68
PALEN

これは少し遅すぎるかもしれませんが、将来の参考のためにこれを追加したかっただけです:

_def clearLayout(layout):
  while layout.count():
    child = layout.takeAt(0)
    if child.widget():
      child.widget().deleteLater()
_

Qt docsからの変更 http://doc.qt.io/qt-5/qlayout.html#takeAt 。 whileループまたはforループでレイアウトから子を削除する場合、レイアウト内の各子アイテムのインデックス#を効果的に変更していることに注意してください。そのため、for i in range()ループを使用すると問題が発生します。

22
Nadeem Douba

新しいウィジェットをレイアウトに配置する必要がない場合、PALENからの回答はうまく機能します。

for i in reversed(range(layout.count())): 
    layout.itemAt(i).widget().setParent(None)

ただし、レイアウトを何回も空にしたり、多くのウィジェットで埋めたりすると、ある時点で「セグメンテーション違反(コアダンプ)」が発生します。レイアウトはウィジェットのリストを保持しており、このリストのサイズは制限されているようです。

その方法でウィジェットを削除する場合:

for i in reversed(range(layout.count())): 
    widgetToRemove = layout.itemAt(i).widget()
    # remove it from the layout list
    layout.removeWidget(widgetToRemove)
    # remove it from the gui
    widgetToRemove.setParent(None)

その問題は発生しません。

17
Blaa_Thor

widgetclose()メソッドを使用できます。

for i in range(layout.count()): layout.itemAt(i).widget().close()
10

それは私がレイアウトをクリアする方法です:

def clearLayout(layout):
    if layout != None:
        while layout.count():
            child = layout.takeAt(0)
            if child.widget() is not None:
                child.widget().deleteLater()
            Elif child.layout() is not None:
                clearLayout(child.layout())
10
user3369214

この問題に対する私の解決策は、QWidgetのsetLayoutメソッドをオーバーライドすることです。次のコードは、すでに表示されているアイテムを含む場合と含まない場合がある新しいレイアウトにレイアウトを更新します。新しいレイアウトオブジェクトを作成し、必要なものを追加してからsetLayoutを呼び出すだけです。もちろん、clearLayoutを呼び出してすべてを削除することもできます。

def setLayout(self, layout):
    self.clearLayout()
    QWidget.setLayout(self, layout)

def clearLayout(self):
    if self.layout() is not None:
        old_layout = self.layout()
        for i in reversed(range(old_layout.count())):
            old_layout.itemAt(i).widget().setParent(None)
        import sip
        sip.delete(old_layout)
3
joshua

ドキュメントから:

レイアウトからウィジェットを削除するには、removeWidget()を呼び出します。ウィジェットでQWidget.hide()を呼び出すと、QWidget.show()が呼び出されるまでウィジェットがレイアウトから効果的に削除されます。

removeWidgetQLayoutから継承されているため、QGridLayoutメソッドにはリストされていません。

2
user395760

私が使う:

    while layout.count() > 0: 
        layout.itemAt(0).setParent(None)
2
SoloPilot

これは実際にスタックオーバーフローの質問に実際に答えたのですが、ここでの答えはすべて少し間違っていることがわかりました。 (はい、質問はすべてのウィジェットを削除することであることを知っています)ほとんどのウィジェットの問題は、ネストされたレイアウトを考慮していないことですそしてその中のすべてのレイアウト。ここにあります:

def clearLayout(layout):
print("-- -- input layout: "+str(layout))
for i in reversed(range(layout.count())):
    layoutItem = layout.itemAt(i)
    if layoutItem.widget() is not None:
        widgetToRemove = layoutItem.widget()
        print("found widget: " + str(widgetToRemove))
        widgetToRemove.setParent(None)
        layout.removeWidget(widgetToRemove)
    Elif layoutItem.spacerItem() is not None:
        print("found spacer: " + str(layoutItem.spacerItem()))
    else:
        layoutToRemove = layout.itemAt(i)
        print("-- found Layout: "+str(layoutToRemove))
        clearLayout(layoutToRemove)

すべてのUIタイプを説明しているわけではありませんが、よくわかりません。お役に立てれば!

1

スタックウィジェットを使用して既知のビュー間でスワップし、表示されたインデックスをフリップするだけの場合、単一のウィジェットをレイアウトに追加および削除するよりも簡単なソリューションがいくつかあります。

allウィジェットの子を置き換えたい場合は、QObject関数findChildrenを使用してください。しかし、テンプレート関数がpyqtでどのようにラップされているのかわかりません。ただし、ウィジェットを知っている場合は、名前でウィジェットを検索することもできます。

1
        for i in reversed (range(layout.count())):
            layout.itemAt(i).widget().close()
            layout.takeAt(i)

または

        for i in range(layout.count()):
            layout.itemAt(0).widget().close()
            layout.takeAt(0)
0
borovsky