如何在 QLayout 中查找给定类型的小部件?

Posted

技术标签:

【中文标题】如何在 QLayout 中查找给定类型的小部件?【英文标题】:How to find widgets of a given type in a QLayout? 【发布时间】:2015-07-21 18:07:38 【问题描述】:

我可以通过这种方式找到QRadioButton

for(int i = 0; i < ui->verticalLayout->count(); i++)

    QRadioButton* r = qobject_cast<QRadioButton*>(ui->verticalLayout->itemAt(i)->widget());
    if(r->isChecked())
        //found it!

但我不喜欢这种迭代元素的方式,我想使用foreach 构造。 我的第一次尝试失败了:

foreach(QRadioButton* child, ui->verticalLayout->findChildren<QRadioButton*>())

    if(child->isChecked())
        //found it!

问题是ui-&gt;verticalLayout-&gt;findChildren&lt;QRadioButton*&gt;() 返回零个元素。它也不返回带有findChildren&lt;QObject*&gt;() 的元素。有人可以解释一下这种行为吗?

注意:this问题的标题与我的几乎相同,但它与python Qt有关,对我没有任何帮助。

儿童与元素?

通过实验,我发现ui-&gt;verticalLayout-&gt;children().count() 返回零,而ui-&gt;verticalLayout-&gt;count() 返回我在verticalLayout 中拥有的元素数。这意味着itemAt(i)findChild&lt;QRadioButton*&gt;() 不会访问同一个列表。查看children() 上的 Qt 文档对我没有帮助。

有人可以给我指出一个关于 Qt 子父概念的好材料吗?我假设这与访问我想要完成的嵌套对象无关。

编辑

正如 Kuba Ober 所建议的,this question 的答案包含有关另一个主题的宝贵信息,而他的回答澄清了我关于布局子级的问题。因此,这不是一个重复的问题。

【问题讨论】:

Qt - iterating through QRadioButtons的可能重复 我已经修改了我的答案以过滤小部件类型。 @demonplus 另一个问题更具体,并且有一个关于使用QButtonGroup 的有价值的答案。我暂时将它们分开。 【参考方案1】:

QObject 孩子的意义上说,这些小部件不是布局的孩子——它们是父窗口小部件的孩子。 QWidget 只能是另一个 QWidget 的子级 - 因此您不能期望小部件成为布局的子级。虽然new QWidget(new QWidget()) 有效,但new QWidget(new QHBoxLayout()) 不会编译。

您可以按如下方式迭代小部件的给定类型的子级:

// C++11
for (auto button : findChildren<QRadioButton*>()) if (button->isChecked()) 
  ...


// C++98
Q_FOREACH (QWidget * button, findChildren<QRadioButton*>())
  if (button->isChecked()) 
    ...
  

如果您使用的是 C++11,则应使用 range-based for loop,而不是现在已过时的 foreachQ_FOREACH

要迭代由布局管理的子小部件,您需要一个用于布局的迭代器适配器。例如:

#include <QLayout>
#include <QDebug>
#include <QPointer>
#include <utility>

template<class WT> class IterableLayoutAdapter;

template<typename WT>
class LayoutIterator 
   QPointer<QLayout> m_layout;
   int m_index;
   friend class IterableLayoutAdapter<WT>;
   LayoutIterator(QLayout * layout, int dir) :
      m_layout(layout), m_index(dir>0 ? -1 : m_layout->count()) 
      if (dir > 0) ++*this;
   
   friend QDebug operator<<(QDebug dbg, const LayoutIterator & it) 
      return dbg << it.m_layout << it.m_index;
   
   friend void swap(LayoutIterator& a, LayoutIterator& b) 
      using std::swap;
      swap(a.m_layout, b.m_layout);
      swap(a.m_index, b.m_index);
   
public:
   LayoutIterator() : m_index(0) 
   LayoutIterator(const LayoutIterator & o) :
      m_layout(o.m_layout), m_index(o.m_index) 
   LayoutIterator(LayoutIterator && o)  swap(*this, o); 
   LayoutIterator & operator=(LayoutIterator o) 
      swap(*this, o);
      return *this;
   
   WT * operator*() const  return static_cast<WT*>(m_layout->itemAt(m_index)->widget()); 
   const LayoutIterator & operator++() 
      while (++m_index < m_layout->count() && !qobject_cast<WT*>(m_layout->itemAt(m_index)->widget()));
      return *this;
   
   LayoutIterator operator++(int) 
      LayoutIterator temp(*this);
      ++*this;
      return temp;
   
   const LayoutIterator & operator--() 
      while (!qobject_cast<WT*>(m_layout->itemAt(--m_index)->widget()) && m_index > 0);
      return *this;
   
   LayoutIterator operator--(int) 
      LayoutIterator temp(*this);
      --*this;
      return temp;
   
   bool operator==(const LayoutIterator & o) const  return m_index == o.m_index; 
   bool operator!=(const LayoutIterator & o) const  return m_index != o.m_index; 
;

template <class WT = QWidget>
class IterableLayoutAdapter 
   QPointer<QLayout> m_layout;
public:
   typedef LayoutIterator<WT> const_iterator;
   IterableLayoutAdapter(QLayout * layout) : m_layout(layout) 
   const_iterator begin() const  return const_iterator(m_layout, 1); 
   const_iterator end() const  return const_iterator(m_layout, -1); 
   const_iterator cbegin() const  return const_iterator(m_layout, 1); 
   const_iterator cend() const  return const_iterator(m_layout, -1); 
;

template <class WT = QWidget>
class ConstIterableLayoutAdapter : public IterableLayoutAdapter<const WT> 
public:
   ConstIterableLayoutAdapter(QLayout * layout) : IterableLayoutAdapter<const WT>(layout) 
;

用法如下:

#include <QApplication>
#include <QLabel>
#include <QHBoxLayout>

int main(int argc, char ** argv) 
   QApplication app(argc, argv);
   tests();
   QWidget a, b1, b3;
   QLabel b2;
   QHBoxLayout l(&a);
   l.addWidget(&b1);
   l.addWidget(&b2);
   l.addWidget(&b3);

   // Iterate all widget types as constants
   qDebug() << "all, range-for";
   for (auto widget : ConstIterableLayoutAdapter<>(&l)) qDebug() << widget;
   qDebug() << "all, Q_FOREACH";
   Q_FOREACH (const QWidget * widget, ConstIterableLayoutAdapter<>(&l)) qDebug() << widget;

   // Iterate labels only
   qDebug() << "labels, range-for";
   for (auto label : IterableLayoutAdapter<QLabel>(&l)) qDebug() << label;
   qDebug() << "labels, Q_FOREACH";
   Q_FOREACH (QLabel * label, IterableLayoutAdapter<QLabel>(&l)) qDebug() << label;

一些基本测试如下所示:

void tests() 
   QWidget a, b1, b3;
   QLabel b2;
   QHBoxLayout l(&a);

   IterableLayoutAdapter<> l0(&l);
   auto i0 = l0.begin();
   qDebug() << i0; Q_ASSERT(i0 == l0.begin() && i0 == l0.end());

   l.addWidget(&b1);
   l.addWidget(&b2);
   l.addWidget(&b3);

   IterableLayoutAdapter<> l1(&l);
   auto i1 = l1.begin();
         qDebug() << i1; Q_ASSERT(i1 == l1.begin() && i1 != l1.end());
   ++i1; qDebug() << i1; Q_ASSERT(i1 != l1.begin() && i1 != l1.end());
   ++i1; qDebug() << i1; Q_ASSERT(i1 != l1.begin() && i1 != l1.end());
   ++i1; qDebug() << i1; Q_ASSERT(i1 != l1.begin() && i1 == l1.end());
   --i1; qDebug() << i1; Q_ASSERT(i1 != l1.begin() && i1 != l1.end());
   --i1; qDebug() << i1; Q_ASSERT(i1 != l1.begin() && i1 != l1.end());
   --i1; qDebug() << i1; Q_ASSERT(i1 == l1.begin() && i1 != l1.end());

   IterableLayoutAdapter<QLabel> l2(&l);
   auto i2 = l2.begin();
         qDebug() << i2; Q_ASSERT(i2 == l2.begin() && i2 != l2.end());
   ++i2; qDebug() << i2; Q_ASSERT(i2 != l2.begin() && i2 == l2.end());
   --i2; qDebug() << i2; Q_ASSERT(i2 == l2.begin() && i2 != l2.end());

【讨论】:

以上是关于如何在 QLayout 中查找给定类型的小部件?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过拖放获取鼠标下QLayout中的小部件?

如何计算存储在 Gtk::Grid 中的小部件?

如何在给定宽度的小部件中移动文本

用户在不使用 QLayout 的情况下扩展/调整 QTextBrowser 小部件的大小

从 QLayout 中删除 QWidgets?

QLayout 中的重叠小部件