如何清除父窗口小部件中的所有窗口小部件?

sar*_*nan 18 qt qwidget

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

gal*_*tte 23

以前的答案是错误的!! 你不能findChildren用来删除小部件的子节点,因为Qt4 findChildren 递归地列出了子节点.因此,您将删除子项的子项,然后可能会删除两次,可能会导致您的应用程序崩溃.

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

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

  • 如果你使用的是Qt5,那么将Qt :: FindDirectChildrenOnly标志传递给findChild(当问题被提出时它不存在...)
  • 使用QLayout函数列出项目,
  • 使用QObject :: children,对于每个测试,如果它是使用isWidgetType()或强制转换的小部件
  • 在循环中使用findChild()并删除结果,直到它返回空指针

  • 您还可以在`findChildren`上使用`Qt :: FindDirectChildrenOnly`来避免双重删除 (3认同)

Mat*_*uhn 17

为了处理@galinette指出的递归问题,你可以在while循环中删除小部件

while ( QWidget* w = findChild<QWidget*>() )
    delete w;
Run Code Online (Sandbox Code Playgroud)

  • 这是我认为最合适的答案 (2认同)

Man*_*d3r 6

来自Qt docs

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

QLayoutItem *child;
while ((child = layout->takeAt(0)) != 0) {
    ...
    delete child;
}
Run Code Online (Sandbox Code Playgroud)


Edw*_*anc 6

总结和补充:

对于一行Qt5:

qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
Run Code Online (Sandbox Code Playgroud)

对于很多孩子的Qt5,请使用setUpdatesEnabled():

parentWidget->setUpdatesEnabled(false);
qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
parentWidget->setUpdatesEnabled(true);
Run Code Online (Sandbox Code Playgroud)

请注意,这并非异常安全!虽然此时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); }
};
Run Code Online (Sandbox Code Playgroud)

...

UpdatesEnabledHelper helper(parentWidget);
qDeleteAll(parentWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
Run Code Online (Sandbox Code Playgroud)

对于Qt4:

QList<QWidget*> childWidgets = parentWidget->findChildren<QWidget*>();
foreach(QWidget* widget, childWidgets)
    if (widget->parentWidget() == parentWidget)
        delete widget;
Run Code Online (Sandbox Code Playgroud)

从QLayout中删除可在Qt4和Qt5中使用:

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

QObject(以及因此QWidgets)在其(QObject)析构函数中自动地将其自身从其父级移除。


Yul*_*aya -6

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

QList<QWidget *> widgets = findChildren<QWidget *>();
foreach(QWidget * widget, widgets)
{
    delete widget;
}
Run Code Online (Sandbox Code Playgroud)

  • Qt 还提供了一个名为 qDeleteAll 的函数,它接受一个容器并删除容器中的每个项目。所以你可以将其简化为 qDeleteAll(findChildren&lt;QWidget*&gt;()); (9认同)
  • 如果有很多孩子,您也可以考虑 setUpdatesEnabled(false); qDeleteAll(findChildren&lt;QWidget*&gt;()); setUpdatesEnabled(真); (3认同)