如何在QLayout中查找给定类型的小部件
How to find widgets of a given type in a QLayout?
我可以这样找到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->verticalLayout->findChildren<QRadioButton*>()
返回零元素。它也不返回含有findChildren<QObject*>()
的元素。有人能解释一下这种行为吗?
注意:这个问题的标题几乎与我的相同,但它与python Qt有关,并且不包含任何对我有用的信息。
子元素vs元素?
实验我认为ui->verticalLayout->children().count()
返回零,其中ui->verticalLayout->count()
返回我在verticalLayout
中拥有的元素数量。这意味着itemAt(i)
和findChild<QRadioButton*>()
不能访问同一个列表。查看children()
上的Qt文档对我没有帮助。
有人能告诉我一个关于Qt孩子父母概念的好材料吗?我假设这与访问嵌套对象无关,而这正是我试图完成的。
编辑
根据Kuba Ober的建议,这个问题的答案包含了关于另一个主题的有价值的信息,而他的回答澄清了我关于布局的子元素的问题。因此这不是一个重复的问题。这些小部件不是布局的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,你应该使用基于范围的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 < 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());
}
- QT如何检查表格小部件类型
- 使用类型特征的部分类专用化
- 如何以类型的安全方式分配UINT32_T :: MAX和UINT64_T的最小值
- 如何计算浮点数据类型的范围、最大值、最小值
- 根据浮点数选择最小整数类型
- 从模板继承<类型名 T、T 最大值、T 最小值>具有多个类型名模板参数的结构
- 从较小类型的指针定义的范围构造向量
- 为什么 std::ssize 被强制为其有符号大小类型的最小大小
- 针对多种类型的部分类模板专用化
- 写一个最小的自定义操作员:std :: Sort需要std :: __ lg为我的类型解释
- 在磁盘上写作时,我应该使用最小的类型
- 在另一类中更改小部件类型的行为
- 类型 *阵列的最小或最大值的类功能 *
- 小标量类型和谷歌协议缓冲区
- 在转换为较小的数值类型之前执行范围检查的安全、跨平台方法是什么
- 如何处理警告:从较小的整数类型int转换为int*
- 无法使用 glm::vec2 作为矩阵的标量类型并使用线性最小二乘法求解
- 模板函数,生成从最小到每种类型的随机值
- 在小对象优化中调试崩溃以进行类型擦除
- C++ 创建小部件数组