問題描述
我可以通過這種方式找到 QRadioButton
:
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!
}
但我不喜歡這種迭代元素的方式,并希望使用 foreach
構造.我的第一次嘗試失敗了:
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!
}
問題在于 ui->verticalLayout->findChildren
返回零元素.它也不返回帶有 findChildren
的元素.有人可以解釋一下這種行為嗎?
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?
注意:這個標題 問題與我的幾乎相同,但它與python Qt有關,并且不包含任何對我有用的信息.
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.
實驗上我認為 ui->verticalLayout->children().count()
返回零,其中 ui->verticalLayout->count()
返回我在 verticalLayout
中的元素數量.這意味著 itemAt(i)
和 findChild
不會訪問同一個列表.查看關于 children()
的 Qt 文檔對我沒有幫助.
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.
有人能給我指點關于 Qt 子父概念的好材料嗎?我假設這與訪問嵌套對象無關,而這正是我想要完成的.
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.
正如 Kuba Ober 所建議的,這個問題的答案包含關于另一個主題的寶貴信息,而他的回答澄清了我關于布局子項的問題.因此這不是一個重復的問題.
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.
推薦答案
就 QObject
子項而言,小部件不是布局的子項 - 它們是父小部件的子項.QWidget
只能是另一個 QWidget
的子項 - 因此您不能期望小部件是布局的子項.雖然 new QWidget(new QWidget())
有效,但 new QWidget(new QHBoxLayout())
不會編譯.
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()) {
...
}
如果你使用 C++11,你應該使用 range-基于 for 循環,而不是現在過時的 foreach
或 Q_FOREACH
.
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) {}
};
用法如下:
#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 中查找給定類型的小部件?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!