Qt获取布局中的子控件

41

我试图隐藏布局中的所有小部件。但是似乎 findChildren 对于布局无效。

这是我的示例代码:

QLayout * layout = widget -> findChild<QLayout *> (layoutName);
QList<QWidget *> list = layout -> findChildren<QWidget *> ();

cout << list.size() << endl;

size为0,但在这个布局中我有一些小部件。但如果我尝试从父小部件获取小部件,则相同的代码可以正常工作。

我该如何从适当的布局中获取它们?

7个回答

45
布局不会“注入”父-子树结构,因此小部件保持其父小部件的(直接)子元素。
您可以改用 QLayout::count()QLayout::itemAt()

11
重点是布局可以成为小部件的子项(因为它们都继承了QObject),但小部件不能成为布局的子项。小部件必须有另一个小部件作为其父项,而QLayout没有继承QWidget。布局将其包含的每个项目都包装在QLayoutItem中,因此需要使用一组不同的API来访问底层对象。 - ekhumoro
很遗憾这条评论已经四年了。即使到今天,Qt仍然通过私有的d_ptr和其列表属性来跟踪其中的小部件,没有公共API... - AIDoubt

43

您可以简单地遍历布局的项,使用itemAt(),然后测试该项是否为小部件:

for (int i = 0; i < gridLayout->count(); ++i)
{
  QWidget *widget = gridLayout->itemAt(i)->widget();
  if (widget != NULL)
  {
    widget->setVisible(false);
  }
  else
  {
    // You may want to recurse, or perform different actions on layouts.
    // See gridLayout->itemAt(i)->layout()
  }
}

11

已经很晚了,但如果还有像我一样来到这里的人,这是我的解决方案: 我尝试了 @braggPeaks 的答案(与 @Frank Osterfeld 的答案相同),但失败了。然后我进行了修改,现在它完美地工作了。(我不知道为什么它能够工作,因为我的布局没有空项,但我仍然必须检查它是否有。)

for (int i = 0; i < this->layout->count(); ++i) {
    QWidget *w = this->layout->itemAt(i)->widget();
    if(w != NULL)
        w->setVisible(false);
}

必须在子类中实现以返回索引处的布局项。如果没有这样的项,则该函数必须返回0。以上引自https://doc.qt.io/qt-5/qlayout.html#itemAt - stdcerr

2

由于布局不是部件层次结构的一部分,因此必须从父级查询部件,然后可以使用indexOf查看它是否属于并确定其位置。

  QLayout * top_l= layout(); // The parent widgets layout
   // Find your layout that you want to search inside
   QHBoxLayout * hbox = top_l->findChild<QHBoxLayout*>(QString("horizontalLayout_2"));
    if (hbox != 0) {
        std::cout << "Found horizontalLayout_2!"<<std::endl;
        QPushButton * st = findChild<QPushButton*>(QString("startButton"));

        if (st != 0) {
            std::cout << "Found startButton in top level widget"<<std::endl;
            int idx = hbox->indexOf(st);
            if (idx >=0) {
                std::cout << "Found startButton in hbox layout at location : "
                          <<idx<<std::endl;
            }
        }
    };

1

回应一篇旧文章,但我想要一个简单的方法来禁用布局中包含的所有小部件或任何子布局。这对我的目的起作用:

void setEnabledWidgetsInLayout(QLayout *layout, bool enabled)
{
   if (layout == NULL)
      return;

   QWidget *pw = layout->parentWidget();
   if (pw == NULL)
      return;

   foreach(QWidget *w, pw->findChildren<QWidget*>())
   {
      if (isChildWidgetOfAnyLayout(layout,w))
         w->setEnabled(enabled);
   }
}

bool isChildWidgetOfAnyLayout(QLayout *layout, QWidget *widget)
{
   if (layout == NULL or widget == NULL)
      return false;

   if (layout->indexOf(widget) >= 0)
      return true;

   foreach(QObject *o, layout->children())
   {
      if (isChildWidgetOfAnyLayout((QLayout*)o,widget))
         return true;
   }

   return false;
}

1

我认为使用QWidget作为容器并将您的小部件放在该“容器小部件”中会更容易,这样您可以通过在“容器小部件”上调用findChildren来访问您的小部件:

auto children = ui->containerWidget->findChildren<QWidget *>();
for (auto child : children) {
    child->setVisible(false);
}

在我的情况下,已经有一个GroupBox作为水平布局的父级。因此,将ui->layout->findChildren更改为ui->groupBox->findChildren就解决了问题。 - atakli

-1
你是否尝试过使用children()方法而不是findChildren()方法?也许你从widget-> findChild<QLayout *>(layoutName)方法中获取了一个“错误”的布局。试着在创建布局后立即查找子项,以确保布局正确。这样做可以确定哪个函数有问题。

是的,我尝试了children(),但没有成功。我无法在创建后进行检查,因为它是从.ui文件加载的...对于小部件运作良好...问题只出现在布局中... - Alex Ivasyuv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接