web-dev-qa-db-ja.com

親ウィジェットのすべてのウィジェットをクリアする方法は?

コンストラクターQWidget(QWidget *parent)を使用しています。この親ウィジェットには、多くの子ウィジェットが含まれています。実行時に親からすべての子ウィジェットをクリアする必要があります。これどうやってするの?

19
saravanan

前の答えは間違っています!! Qt4のfindChildren再帰的には子をリストするため、findChildrenを使用してウィジェットの子を削除することはできません。したがって、子の子を削除します。その後、子が2回削​​除され、アプリがクラッシュする可能性があります。

より一般的には、Qtでは、QObjectポインターのリストを取得し、それらを1つずつ削除することは危険です。オブジェクトを破棄すると、親の所有権メカニズムのため、またはdestroyed()信号をdeleteLater()スロットに送信します。したがって、リストの最初のオブジェクトを破棄すると、次のオブジェクトが無効になる可能性があります。

次のいずれかの方法で子ウィジェットを一覧表示する必要があります。

  • Qt5を使用している場合にfindChildにQt :: FindDirectChildrenOnlyフラグを渡す(質問されたときに存在しなかった...)
  • アイテムを一覧表示するためのQLayout関数の使用、
  • QObject :: childrenを使用し、テストごとに、isWidgetType()を使用するウィジェットかキャストか
  • ループでfindChild()を使用し、nullポインターが返されるまで結果を削除します
22
galinette

@galinetteによって指摘された再帰性の問題に対処するには、whileループでウィジェットを削除するだけです。

while ( QWidget* w = findChild<QWidget*>() )
    delete w;
15
Matthias Kuhn

要約と補足:

1行のQt5の場合:

qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));

多くの子のQt5の場合、setUpdatesEnabled()を使用します。

parentWidget->setUpdatesEnabled(false);
qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
parentWidget->setUpdatesEnabled(true);

これは例外安全ではないことに注意してください!現時点では、Qtはここで例外をスローするようには見えませんが、destroyed()シグナルは、スローするコードに接続されているか、オーバーライドされたObject :: childEvent(QChildEvent *)がスローされる可能性があります。

ヘルパークラスを使用することをお勧めします。

class UpdatesEnabledHelper
{
    QWidget* m_parentWidget;
public:
    UpdatesEnabledHelper(QWidget* parentWidget) : m_parentWidget(parentWidget) { parentWidget->setUpdatesEnabled(false); }
    ~UpdatesEnabledHelper() { m_parentWidget->setUpdatesEnabled(true); }
};

.。

UpdatesEnabledHelper helper(parentWidget);
qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));

Qt4の場合:

QList<QWidget*> childWidgets = parentWidget->findChildren<QWidget*>();
foreach(QWidget* widget, childWidgets)
    if (widget->parentWidget() == parentWidget)
        delete widget;

QLayoutからの削除は、Qt4とQt5の両方で機能します。

QLayoutItem* child;
while (NULL != (child = layout->takeAt(0))) // or nullptr instead of NULL
    delete child;

QObject(したがってQWidgets)は、(QObject)デストラクタで親から(自動的に)自分自身を削除します。

6
Edward LeBlanc

Qtから docs

次のコードフラグメントは、レイアウトからすべてのアイテムを削除する安全な方法を示しています。

QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
    ...
    delete child;
}
5
ManuelSchneid3r