qt qwidget

qt - ¿Cómo borrar todos los widgets en los widgets principales?



qwidget (5)

Estoy usando el constructor QWidget(QWidget *parent) . Este widget principal contiene muchos widgets secundarios. Necesito borrar todos los widgets secundarios del padre en el tiempo de ejecución. ¿Cómo puedo hacer esto?


Desde Qt docs

El siguiente fragmento de código muestra una forma segura de eliminar todos los elementos de un diseño:

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


La respuesta anterior es incorrecta !! No puede utilizar findChildren para eliminar los elementos findChildren de un widget, porque los findChildren de findChildren qt4 de findChildren recursivamente findChildren los elementos findChildren . Por lo tanto, eliminará los hijos de los niños, que luego pueden eliminarse dos veces, lo que podría bloquear su aplicación.

Más generalmente, en Qt, es peligroso tomar una lista de punteros QObject y eliminarlos uno por uno, ya que destruir un objeto puede destruir otros objetos en cadena, debido al mecanismo de propiedad principal, o al conectar una señal destroyed() a un deleteLater() ranura. Por lo tanto, destruir los primeros objetos en la lista puede invalidar los siguientes.

Necesitas listar widgets de niños ya sea por:

  • Pasando la marca Qt :: FindDirectChildrenOnly para encontrarChild si está usando Qt5 (que no existía cuando se hizo la pregunta ...)
  • Usando las funciones de QLayout para listar artículos,
  • Usando QObject :: children, y para cada prueba si es un widget que usa isWidgetType () o un cast
  • Usar findChild () en un bucle y eliminar el resultado hasta que devuelva un puntero nulo

Para solucionar el problema de recursividad señalado por @galinette, puede eliminar los widgets en un bucle de tiempo.

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


Puedes usar lo siguiente en tu clase de widget principal:

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


Resumiendo y complementando:

Para Qt5 en una línea:

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

Para Qt5 para muchos niños, usando setUpdatesEnabled ():

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

Tenga en cuenta que esto no es una excepción segura! Si bien, en este momento, Qt no parece lanzar excepciones, la señal destruida () podría estar conectada a un código que arroja, o podría lanzar un Object :: childEvent (QChildEvent *) anulado.

Mejor sería usar una clase de ayuda:

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));

Para Qt4:

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

La eliminación de QLayout funciona tanto en Qt4 como en Qt5:

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

Los QObjects (y por lo tanto QWidgets) se eliminan a sí mismos (automáticamente) de su padre en su destructor (QObject).