【问题标题】:Qt - Clear all widgets from inside a QWidget's layoutQt - 从 QWidget 的布局中清除所有小部件
【发布时间】:2014-03-25 18:57:01
【问题描述】:

我在对话框中有一个QWidget。在程序运行的过程中,几个QCheckBox * 对象被添加到布局中,如下所示:

QCheckBox *c = new QCheckBox("Checkbox text");
ui->myWidget->layout()->addWidget(c);

这适用于所有复选框。但是,我的对话框中还有一个名为“clear”的QPushButton,当按下它时应该清空myWidget 中的所有内容,使其保持空白,就像添加任何QCheckboxes 之前一样。我一直在网上和文档中四处寻找,但我很难找到一种方法来做到这一点。我发现了this 问题,我认为这与我的问题相似,并尝试了他们的解决方案:

void myClass::on_clear_clicked()
{
  while(ui->myWidget->layout()->count() > 0)
  {
    QLayoutItem *item = ui->myWidget->layout()->takeAt(0);
    delete item;
  }
}

然而,这似乎没有做任何事情。值得注意的是,我不确定这是否正确地从他的回答中翻译出来;应该如何实现给定的功能有点不清楚,所以我做了我最有根据的猜测。如果有人知道我可以在上面进行哪些更改以使其工作(或只是一种不同的工作方式),将不胜感激。

【问题讨论】:

    标签: c++ qt qwidget


    【解决方案1】:

    你可以试试这个:

        while ( QLayoutItem* item = ui->myWidget->layout()->takeAt( 0 ) )
        {
            Q_ASSERT( ! item->layout() ); // otherwise the layout will leak
            delete item->widget();
            delete item;
        }
    

    【讨论】:

    • ...对不起,我以为这行得通,但实际上并没有:/谢谢
    • item->widget() 如果布局项是分隔符或子布局,则返回 0。这会崩溃
    • 这会起作用,但您必须检查item->widget() 是否有效,并且最好调用对象的deleteLater 而不是仅仅删除它。只需用 if (auto widget = item->widget()) widget->deleteLater(); 修补该行即可
    • @iKlsR 两者都不是真的:delete 在传递空指针时定义了行为 - 它什么也不做。任何时候都可以删除小部件,除非此代码在从小部件调用的插槽中并且它使用小部件上下文(即this)。
    • 通过添加Q_ASSERT(sender() != item->widget() || ! sender()),此代码会稍微更有弹性——这将避免由于删除发件人小部件而导致难以调试的问题。在这种情况下,失败会容易得多。它不会对发布版本的性能产生影响。
    【解决方案2】:

    布局的美妙之处在于它们会自动处理小部件的删除。所以你真正需要的只是迭代小部件,你就完成了。由于您想清除给定小部件的所有子级,只需执行以下操作:

    for (auto widget: ui->myWidget::findChildren<QWidget*>
                                                ({}, Qt::FindDirectChildrenOnly))
      delete widget;
    

    完全无需担心布局。无论孩子是否由布局管理,这都有效。

    如果您想真正做到正确,则需要忽略作为子小部件但是独立窗口的小部件。如果这是通用的,情况就是这样 库代码:

    for (auto widget: ui->myWidget::findChildren<QWidget*>
                                                ({}, Qt::FindDirectChildrenOnly)) 
      if (! widget->windowFlags() & Qt::Window) delete widget;
    

    或者,如果您只想删除由给定布局及其子布局管理的子级:

    void clearWidgets(QLayout * layout) {
       if (! layout)
          return;
       while (auto item = layout->takeAt(0)) {
          delete item->widget();
          clearWidgets(item->layout());
       }
    }
    

    【讨论】:

    • clearWidgets 递归函数是我发现能够删除以编程方式创建的嵌套布局/小部件的唯一方法。没有 UI 句柄会让事情变得很困难,但上面的功能是我需要的秘诀!
    【解决方案3】:

    鉴于您有一个由包含小部件的级联布局组成的小部件层次结构,那么您最好选择以下方法。

    第 1 步:删除所有小部件

        QList< QWidget* > children;
        do
        {
           children = MYTOPWIDGET->findChildren< QWidget* >();
           if ( children.count() == 0 )
               break;
           delete children.at( 0 );
        }
        while ( true );
    

    第 2 步:删除所有布局

        if ( MYTOPWIDGET->layout() )
        {
            QLayoutItem* p_item;
            while ( ( p_item = MYTOPWIDGET->layout()->takeAt( 0 ) ) != nullptr )
                delete p_item;
            delete MYTOPWIDGET->layout();
        }
    

    在第 2 步之后,您的 MYTOPWIDGET 应该是干净的。

    【讨论】:

      【解决方案4】:

      PySide2 解决方案:

      from PySide2 import QtWidgets
      
      
      def clearLayout(layout: QtWidgets.QLayout):
          for i in reversed(range(layout.count())):
              item = layout.itemAt(i)
              if isinstance(item, QtWidgets.QLayout):
                  clearLayout(item)
              elif item.widget():
                  item.widget().setParent(None)
              else:
                  layout.removeItem(item)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-05-30
        • 2023-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-28
        相关资源
        最近更新 更多