Как очистить все виджеты в родительских виджетах? - PullRequest
17 голосов
/ 15 октября 2010

Я использую конструктор QWidget(QWidget *parent). Этот родительский виджет содержит много дочерних виджетов. Мне нужно очистить все дочерние виджеты от родителя во время выполнения. Как я могу это сделать?

Ответы [ 5 ]

22 голосов
/ 05 февраля 2013

Предыдущий ответ неверен !! Вы не можете использовать findChildren, чтобы удалить дочерние элементы виджета, потому что Qt4 findChildren рекурсивно перечисляет дочерние элементы. Поэтому вы удалите дочерние элементы детей, которые затем могут быть удалены дважды, что может привести к сбою приложения.

В более общем смысле, в Qt брать список QObject указателей и удалять их по одному опасно, поскольку уничтожение объекта может уничтожить другие объекты по цепочке из-за механизма родительского владения или путем подключения destroyed() сигнал в слот deleteLater(). Поэтому уничтожение первых объектов в списке может сделать недействительными следующие.

Вам нужно перечислить дочерние виджеты либо по:

  • Передача флага Qt :: FindDirectChildrenOnly для findChild, если вы используете Qt5 (которого не было, когда задавался вопрос ...)
  • Использование функций QLayout для перечисления элементов,
  • Использование QObject :: children и для каждого теста, если это виджет, с использованием isWidgetType () или приведением
  • Использование findChild () в цикле и удаление результата до тех пор, пока он не вернет нулевой указатель
14 голосов
/ 13 мая 2014

Чтобы решить проблему рекурсивности, указанную @galinette, вы можете просто удалить виджеты в цикле while

while ( QWidget* w = findChild<QWidget*>() )
    delete w;
5 голосов
/ 04 марта 2016

Суммирование и дополнение:

Для Qt5 в одной строке:

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

Для Qt5 для большого количества детей, используя setUpdatesEnabled ():

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

Обратите внимание, что это не исключение безопасно! Хотя в настоящее время Qt, по-видимому, здесь не генерирует исключения, сигнал destroy () может быть связан с кодом, который выполняет throw, или переопределенным 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;

QObjects (и, следовательно, QWidgets) удаляют себя (автоматически) из своих родителей в своем (QObject) деструкторе.

5 голосов
/ 08 октября 2015

Из Qt документы

Следующий фрагмент кода показывает безопасный способ удаления всех элементов из макета:

QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
    ...
    delete child;
}
0 голосов
/ 15 октября 2010

Вы можете использовать следующее в классе родительского виджета:

QList<QWidget *> widgets = findChildren<QWidget *>();
foreach(QWidget * widget, widgets)
{
    delete widget;
}
...