22

我正在使用构造函数QWidget(QWidget *parent)。这个父小部件包含很多子小部件。我需要在运行时从父级清除所有子小部件。我怎样才能做到这一点?

4

5 回答 5

27

之前的回答错了!!您不能用于findChildren删除小部件的子级,因为 Qt4 会findChildren 递归地列出子级。因此,您将删除子项的子项,这些子项可能会被删除两次,从而可能导致您的应用程序崩溃。

更一般地说,在 Qt 中,获取QObject指针列表并一个一个地删除它们是危险的,因为由于父所有权机制或通过将destroyed()信号连接到deleteLater()插槽,销毁对象可能会链式销毁其他对象。因此,销毁列表中的第一个对象可能会使接下来的对象无效。

您需要通过以下方式列出子小部件:

  • 如果您使用的是 Qt5,则将 Qt::FindDirectChildrenOnly 标志传递给 findChild (在提出问题时不存在...)
  • 使用 QLayout 函数列出项目,
  • 使用 QObject::children,并且对于每个测试它是否是使用 isWidgetType() 或强制转换的小部件
  • 在循环中使用 findChild() 并删除结果,直到它返回一个空指针
于 2013-02-05T08:58:39.307 回答
20

要解决@galinette 指出的递归问题,您可以在while 循环中删除小部件

while ( QWidget* w = findChild<QWidget*>() )
    delete w;
于 2014-05-13T12:17:53.133 回答
10

总结和补充:

对于一行中的 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) 析构函数中(自动)从它们的父级中删除它们自己。

于 2016-03-04T17:17:47.593 回答
6

来自 Qt文档

以下代码片段显示了从布局中删除所有项目的安全方法:

QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
    ...
    delete child;
}
于 2015-10-08T11:08:53.297 回答
-6

您可以在父小部件类中使用以下内容:

QList<QWidget *> widgets = findChildren<QWidget *>();
foreach(QWidget * widget, widgets)
{
    delete widget;
}
于 2010-10-15T08:02:55.153 回答