我正在使用构造函数QWidget(QWidget *parent)
。这个父小部件包含很多子小部件。我需要在运行时从父级清除所有子小部件。我怎样才能做到这一点?
5 回答
之前的回答错了!!您不能用于findChildren
删除小部件的子级,因为 Qt4 会findChildren
递归地列出子级。因此,您将删除子项的子项,这些子项可能会被删除两次,从而可能导致您的应用程序崩溃。
更一般地说,在 Qt 中,获取QObject
指针列表并一个一个地删除它们是危险的,因为由于父所有权机制或通过将destroyed()
信号连接到deleteLater()
插槽,销毁对象可能会链式销毁其他对象。因此,销毁列表中的第一个对象可能会使接下来的对象无效。
您需要通过以下方式列出子小部件:
- 如果您使用的是 Qt5,则将 Qt::FindDirectChildrenOnly 标志传递给 findChild (在提出问题时不存在...)
- 使用 QLayout 函数列出项目,
- 使用 QObject::children,并且对于每个测试它是否是使用 isWidgetType() 或强制转换的小部件
- 在循环中使用 findChild() 并删除结果,直到它返回一个空指针
要解决@galinette 指出的递归问题,您可以在while 循环中删除小部件
while ( QWidget* w = findChild<QWidget*>() )
delete w;
总结和补充:
对于一行中的 Qt5:
qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
对于很多孩子的 Qt5,使用 setUpdatesEnabled():
parentWidget->setUpdatesEnabled(false);
qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
parentWidget->setUpdatesEnabled(true);
请注意,这不是异常安全的!虽然此时 Qt 似乎没有在这里抛出异常,但信号 destroy() 可以连接到确实抛出的代码,或者覆盖的 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) 析构函数中(自动)从它们的父级中删除它们自己。
来自 Qt文档
以下代码片段显示了从布局中删除所有项目的安全方法:
QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
...
delete child;
}
您可以在父小部件类中使用以下内容:
QList<QWidget *> widgets = findChildren<QWidget *>();
foreach(QWidget * widget, widgets)
{
delete widget;
}