如何在QLayout中找到给定类型的窗口小部件? [英] How to find widgets of a given type in a QLayout?

查看:136
本文介绍了如何在QLayout中找到给定类型的窗口小部件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  for(int i = 0; i  count(); i ++)
{
QRadioButton * r = qobject_cast< QRadioButton *>(ui-> verticalLayout- > itemAt(i) - > widget());
if(r-> isChecked())
//找到了!
}

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

  foreach(QRadioButton * child,ui-> verticalLayout-> findChildren< QRadioButton *>())
{
if(child-> isChecked())
//找到了!问题是, ui-> verticalLayout->
}


$ b < > findChildren< QRadioButton *>()
返回零元素。它也不返回 findChildren< QObject *>()的元素。有人可以解释这个行为吗?



注意

孩子vs元素?



实验上我认为 ui-> verticalLayout-> child()。count()返回零,其中 ui-> verticalLayout-> count() verticalLayout 。这意味着 itemAt(i) findChild< QRadioButton *>()不访问同一个列表。查看 children()的Qt文档没有帮助我。



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



编辑



根据Kuba Ober的建议,对此问题的回答包含有关另一主题的有用信息,而他的回答澄清了我关于布局的孩子的问题。因此,这不是一个重复的问题。

解决方案

小部件不是布局的子元素 QObject children - 它们是父窗口小部件的子项。 QWidget 只能是另一个 QWidget 的子级 - 因此你不能期望小部件是布局的子级。虽然新的QWidget(新的QWidget())工程,新的QWidget(新的QHBoxLayout())



您可以按照以下方式迭代给定类型的窗口小部件的子项:

  // C ++ 11 
for(auto button:findChildren< QRadioButton *>())if(button-> isChecked()){
...
} b
$ b // C ++ 98
Q_FOREACH(QWidget * button,findChildren< QRadioButton *>())
if(button-> isChecked()){
...
}

如果使用C ++ 11,请使用基于范围的for循环,而不是现在已过时的 foreach Q_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 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>
return * this;
}
LayoutIterator运算符 - (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);

//将所有窗口小部件类型作为常量迭代
qDebug()<< all,range-for;
for(auto widget:ConstIterableLayoutAdapter<>(& l))qDebug()<<小部件
qDebug()<< all,Q_FOREACH;
Q_FOREACH(const QWidget * widget,ConstIterableLayoutAdapter<>(& l))qDebug()<小部件

//仅迭代标签
qDebug()<< labels,range-for;
for(auto label:IterableLayoutAdapter< QLabel>(& l))qDebug()<标签;
qDebug()<< labels,Q_FOREACH;
Q_FOREACH(QLabel * label,IterableLayoutAdapter< QLabel>(& l))qDebug()<标签;
}

一些初步测试如下:

  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 == l.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());
}


I am able to find the QRadioButton this way:

for(int i = 0; i < ui->verticalLayout->count(); i++)
{
    QRadioButton* r = qobject_cast<QRadioButton*>(ui->verticalLayout->itemAt(i)->widget());
    if(r->isChecked())
        //found it!
}

But I don't like this way of iterating over elements and would like to use the foreach construct. My first attempt fails:

foreach(QRadioButton* child, ui->verticalLayout->findChildren<QRadioButton*>())
{
    if(child->isChecked())
        //found it!
}

Problem is that the ui->verticalLayout->findChildren<QRadioButton*>() returns zero elements. It also returns no elements with findChildren<QObject*>(). Can someone please explain this behaviour?

Note: the title of this question is almost identical to mine, but it is related to python Qt, and does not contain any helpful information for me.

Children vs elements?

Experimentally I figured that ui->verticalLayout->children().count() returns zero where as ui->verticalLayout->count() returns the number of elements I have in the verticalLayout. This implies that itemAt(i) and findChild<QRadioButton*>() do not access the same list. Looking at the Qt documentation on children() did not help me.

Can someone point me to a good material on Qt child parent concepts? I am assuming that this has nothing to do with accesing nested objects which is what I am trying to accomplish.

Edit

As suggested by Kuba Ober, the answers to this question contains valuable information on another topic, whereas his answer makes clarification on my question about children of layout. Thus this is not a duplicate question.

解决方案

The widgets are not children of the layout in the sense of being QObject children - they are children of the parent widget. A QWidget can only be a child of another QWidget - thus you can't ever expect widgets to be layout's children. While new QWidget(new QWidget()) works, new QWidget(new QHBoxLayout()) won't compile.

You could iterate a widget's children of a given type as follows:

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

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

If you're using C++11, you should use the range-based for loop, not the now obsolete foreach or Q_FOREACH.

To iterate the child widgets managed by a layout, you need an iterator adapter for the layout. For example:

#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) {}
};

It's used as follows:

#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;
}

Some rudimentary tests look as follows:

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中找到给定类型的窗口小部件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆