QObject: optimize the common case of findChildren(QString())
Outside tests, all in-tree callers of QObject::findChildren() pass no name to match, and in my experience that is also true for the vast majority of out-of-tree users. Avoid the temporary QString creation in the caller and the repeated QString::isNull() checks in the implementation by overloading findChildren() without a name argument and checking for name.isNull() only once, forking off into separate helper functions. Adjust in-tree callers that used an explicit `QString()` argument in order to pass options, which goes to show that `name` should never have been the first argument of findChilden() in the first place, even though I appreciate the symmetry with findChild() (the use-cases of which, however, are radically different). Change a `findChildren().size() == 0` call found while scanning for findChildren() calls to `!findChild()` as a drive-by. Modernize loops in the various qt_qFindChild{,ren}_helper() overloads to match how the new code looks. [ChangeLog][QtCore][QObject] Added findChildren() overload taking no name (thus optimizing this common case). Change-Id: Ifc56e5438023d079b40c67f11ae274a3e128ad5e Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
parent
1edb51a315
commit
2b50c8bec0
@ -441,7 +441,7 @@ int ArthurStyle::pixelMetric(PixelMetric pm, const QStyleOption *opt, const QWid
|
||||
void ArthurStyle::polish(QWidget *widget)
|
||||
{
|
||||
if (widget->layout() && qobject_cast<QGroupBox *>(widget)) {
|
||||
if (widget->findChildren<QGroupBox *>().size() == 0) {
|
||||
if (!widget->findChild<QGroupBox *>()) {
|
||||
widget->layout()->setSpacing(0);
|
||||
widget->layout()->setContentsMargins(12, 12, 12, 12);
|
||||
} else {
|
||||
|
@ -449,7 +449,7 @@ QListWidget *list = parentWidget->findChild<QListWidget *>(QString(), Qt::FindDi
|
||||
|
||||
|
||||
//! [43]
|
||||
QList<QPushButton *> childButtons = parentWidget.findChildren<QPushButton *>(QString(), Qt::FindDirectChildrenOnly);
|
||||
QList<QPushButton *> childButtons = parentWidget.findChildren<QPushButton *>(Qt::FindDirectChildrenOnly);
|
||||
//! [43]
|
||||
|
||||
//! [44]
|
||||
|
@ -1947,7 +1947,8 @@ void QObject::killTimer(int id)
|
||||
|
||||
Returns all children of this object with the given \a name that can be
|
||||
cast to type T, or an empty list if there are no such objects.
|
||||
Omitting the \a name argument causes all object names to be matched.
|
||||
A null \a name argument causes all objects to be matched, an empty one
|
||||
only those whose objectName is empty.
|
||||
The search is performed recursively, unless \a options specifies the
|
||||
option FindDirectChildrenOnly.
|
||||
|
||||
@ -1967,6 +1968,19 @@ void QObject::killTimer(int id)
|
||||
\sa findChild()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template<typename T> QList<T> QObject::findChildren(Qt::FindChildOptions options) const
|
||||
\overload
|
||||
\since 6.3
|
||||
|
||||
Returns all children of this object that can be cast to type T, or
|
||||
an empty list if there are no such objects.
|
||||
The search is performed recursively, unless \a options specifies the
|
||||
option FindDirectChildrenOnly.
|
||||
|
||||
\sa findChild()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QList<T> QObject::findChildren(const QRegularExpression &re, Qt::FindChildOptions options) const
|
||||
\overload findChildren()
|
||||
@ -2012,24 +2026,46 @@ void QObject::killTimer(int id)
|
||||
\sa QObject::findChildren()
|
||||
*/
|
||||
|
||||
static void qt_qFindChildren_with_name(const QObject *parent, const QString &name,
|
||||
const QMetaObject &mo, QList<void *> *list,
|
||||
Qt::FindChildOptions options)
|
||||
{
|
||||
Q_ASSERT(parent);
|
||||
Q_ASSERT(list);
|
||||
Q_ASSERT(!name.isNull());
|
||||
for (QObject *obj : parent->children()) {
|
||||
if (mo.cast(obj) && obj->objectName() == name)
|
||||
list->append(obj);
|
||||
if (options & Qt::FindChildrenRecursively)
|
||||
qt_qFindChildren_with_name(obj, name, mo, list, options);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void qt_qFindChildren_helper(const QObject *parent, const QString &name,
|
||||
const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
|
||||
{
|
||||
if (name.isNull())
|
||||
return qt_qFindChildren_helper(parent, mo, list, options);
|
||||
else
|
||||
return qt_qFindChildren_with_name(parent, name, mo, list, options);
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
void qt_qFindChildren_helper(const QObject *parent, const QMetaObject &mo,
|
||||
QList<void*> *list, Qt::FindChildOptions options)
|
||||
{
|
||||
Q_ASSERT(parent);
|
||||
Q_ASSERT(list);
|
||||
const QObjectList &children = parent->children();
|
||||
QObject *obj;
|
||||
for (int i = 0; i < children.size(); ++i) {
|
||||
obj = children.at(i);
|
||||
if (mo.cast(obj)) {
|
||||
if (name.isNull() || obj->objectName() == name)
|
||||
list->append(obj);
|
||||
}
|
||||
for (QObject *obj : parent->children()) {
|
||||
if (mo.cast(obj))
|
||||
list->append(obj);
|
||||
if (options & Qt::FindChildrenRecursively)
|
||||
qt_qFindChildren_helper(obj, name, mo, list, options);
|
||||
qt_qFindChildren_helper(obj, mo, list, options);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2042,10 +2078,7 @@ void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re
|
||||
{
|
||||
Q_ASSERT(parent);
|
||||
Q_ASSERT(list);
|
||||
const QObjectList &children = parent->children();
|
||||
QObject *obj;
|
||||
for (int i = 0; i < children.size(); ++i) {
|
||||
obj = children.at(i);
|
||||
for (QObject *obj : parent->children()) {
|
||||
if (mo.cast(obj)) {
|
||||
QRegularExpressionMatch m = re.match(obj->objectName());
|
||||
if (m.hasMatch())
|
||||
@ -2063,18 +2096,13 @@ void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re
|
||||
QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options)
|
||||
{
|
||||
Q_ASSERT(parent);
|
||||
const QObjectList &children = parent->children();
|
||||
QObject *obj;
|
||||
int i;
|
||||
for (i = 0; i < children.size(); ++i) {
|
||||
obj = children.at(i);
|
||||
for (QObject *obj : parent->children()) {
|
||||
if (mo.cast(obj) && (name.isNull() || obj->objectName() == name))
|
||||
return obj;
|
||||
}
|
||||
if (options & Qt::FindChildrenRecursively) {
|
||||
for (i = 0; i < children.size(); ++i) {
|
||||
obj = qt_qFindChild_helper(children.at(i), name, mo, options);
|
||||
if (obj)
|
||||
for (QObject *child : parent->children()) {
|
||||
if (QObject *obj = qt_qFindChild_helper(child, name, mo, options))
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
@ -3593,7 +3621,7 @@ void QMetaObject::connectSlotsByName(QObject *o)
|
||||
const QMetaObject *mo = o->metaObject();
|
||||
Q_ASSERT(mo);
|
||||
const QObjectList list = // list of all objects to look for matching signals including...
|
||||
o->findChildren<QObject *>(QString()) // all children of 'o'...
|
||||
o->findChildren<QObject *>() // all children of 'o'...
|
||||
<< o; // and the object 'o' itself
|
||||
|
||||
// for each method/slot of o ...
|
||||
|
@ -83,6 +83,8 @@ typedef QList<QObject*> QObjectList;
|
||||
|
||||
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QString &name,
|
||||
const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
|
||||
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QMetaObject &mo,
|
||||
QList<void *> *list, Qt::FindChildOptions options);
|
||||
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,
|
||||
const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
|
||||
Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options);
|
||||
@ -167,7 +169,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline QList<T> findChildren(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
|
||||
inline QList<T> findChildren(const QString &aName, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
|
||||
{
|
||||
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
|
||||
QList<T> list;
|
||||
@ -176,6 +178,16 @@ public:
|
||||
return list;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
QList<T> findChildren(Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
|
||||
{
|
||||
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
|
||||
QList<T> list;
|
||||
qt_qFindChildren_helper(this, ObjType::staticMetaObject,
|
||||
reinterpret_cast<QList<void *> *>(&list), options);
|
||||
return list;
|
||||
}
|
||||
|
||||
#if QT_CONFIG(regularexpression)
|
||||
template<typename T>
|
||||
inline QList<T> findChildren(const QRegularExpression &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
|
||||
|
@ -2607,7 +2607,7 @@ void QDockAreaLayout::removePlaceHolder(const QString &name)
|
||||
if (!index.isEmpty())
|
||||
remove(index);
|
||||
const auto groups =
|
||||
mainWindow->findChildren<QDockWidgetGroupWindow *>(QString(), Qt::FindDirectChildrenOnly);
|
||||
mainWindow->findChildren<QDockWidgetGroupWindow *>(Qt::FindDirectChildrenOnly);
|
||||
for (QDockWidgetGroupWindow *dwgw : groups) {
|
||||
index = dwgw->layoutInfo()->indexOfPlaceHolder(name);
|
||||
if (!index.isEmpty()) {
|
||||
@ -3045,7 +3045,7 @@ bool QDockAreaLayout::restoreDockWidget(QDockWidget *dockWidget)
|
||||
{
|
||||
QDockAreaLayoutItem *item = nullptr;
|
||||
const auto groups =
|
||||
mainWindow->findChildren<QDockWidgetGroupWindow *>(QString(), Qt::FindDirectChildrenOnly);
|
||||
mainWindow->findChildren<QDockWidgetGroupWindow *>(Qt::FindDirectChildrenOnly);
|
||||
for (QDockWidgetGroupWindow *dwgw : groups) {
|
||||
QList<int> index = dwgw->layoutInfo()->indexOfPlaceHolder(dockWidget->objectName());
|
||||
if (!index.isEmpty()) {
|
||||
|
@ -431,7 +431,7 @@ void QDockWidgetGroupWindow::destroyOrHideIfEmpty()
|
||||
}
|
||||
|
||||
// Make sure to reparent the possibly floating or hidden QDockWidgets to the parent
|
||||
const auto dockWidgets = findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly);
|
||||
const auto dockWidgets = findChildren<QDockWidget *>(Qt::FindDirectChildrenOnly);
|
||||
for (QDockWidget *dw : dockWidgets) {
|
||||
bool wasFloating = dw->isFloating();
|
||||
bool wasHidden = dw->isHidden();
|
||||
@ -451,7 +451,7 @@ void QDockWidgetGroupWindow::destroyOrHideIfEmpty()
|
||||
dw->show();
|
||||
}
|
||||
#if QT_CONFIG(tabbar)
|
||||
const auto tabBars = findChildren<QTabBar *>(QString(), Qt::FindDirectChildrenOnly);
|
||||
const auto tabBars = findChildren<QTabBar *>(Qt::FindDirectChildrenOnly);
|
||||
for (QTabBar *tb : tabBars)
|
||||
tb->setParent(parentWidget());
|
||||
#endif
|
||||
@ -1056,7 +1056,7 @@ void QMainWindowLayoutState::saveState(QDataStream &stream) const
|
||||
dockAreaLayout.saveState(stream);
|
||||
#if QT_CONFIG(tabbar)
|
||||
const QList<QDockWidgetGroupWindow *> floatingTabs =
|
||||
mainWindow->findChildren<QDockWidgetGroupWindow *>(QString(), Qt::FindDirectChildrenOnly);
|
||||
mainWindow->findChildren<QDockWidgetGroupWindow *>(Qt::FindDirectChildrenOnly);
|
||||
|
||||
for (QDockWidgetGroupWindow *floating : floatingTabs) {
|
||||
if (floating->layoutInfo()->isEmpty())
|
||||
@ -1835,7 +1835,7 @@ QDockAreaLayoutInfo *QMainWindowLayout::dockInfo(QWidget *widget)
|
||||
if (info)
|
||||
return info;
|
||||
const auto groups =
|
||||
parent()->findChildren<QDockWidgetGroupWindow*>(QString(), Qt::FindDirectChildrenOnly);
|
||||
parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
|
||||
for (QDockWidgetGroupWindow *dwgw : groups) {
|
||||
info = dwgw->layoutInfo()->info(widget);
|
||||
if (info)
|
||||
@ -2104,7 +2104,7 @@ bool QMainWindowLayout::plug(QLayoutItem *widgetItem)
|
||||
previousPath = currentHoveredFloat->layoutInfo()->indexOf(widget);
|
||||
// Let's remove the widget from any possible group window
|
||||
const auto groups =
|
||||
parent()->findChildren<QDockWidgetGroupWindow*>(QString(), Qt::FindDirectChildrenOnly);
|
||||
parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
|
||||
for (QDockWidgetGroupWindow *dwgw : groups) {
|
||||
if (dwgw == currentHoveredFloat)
|
||||
continue;
|
||||
@ -2134,7 +2134,7 @@ bool QMainWindowLayout::plug(QLayoutItem *widgetItem)
|
||||
#if QT_CONFIG(dockwidget)
|
||||
// Let's remove the widget from any possible group window
|
||||
const auto groups =
|
||||
parent()->findChildren<QDockWidgetGroupWindow*>(QString(), Qt::FindDirectChildrenOnly);
|
||||
parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
|
||||
for (QDockWidgetGroupWindow *dwgw : groups) {
|
||||
QList<int> path = dwgw->layoutInfo()->indexOf(widget);
|
||||
if (!path.isEmpty())
|
||||
@ -2730,7 +2730,7 @@ void QMainWindowLayout::applyState(QMainWindowLayoutState &newState, bool animat
|
||||
#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
|
||||
QSet<QTabBar*> used = newState.dockAreaLayout.usedTabBars();
|
||||
const auto groups =
|
||||
parent()->findChildren<QDockWidgetGroupWindow*>(QString(), Qt::FindDirectChildrenOnly);
|
||||
parent()->findChildren<QDockWidgetGroupWindow*>(Qt::FindDirectChildrenOnly);
|
||||
for (QDockWidgetGroupWindow *dwgw : groups)
|
||||
used += dwgw->layoutInfo()->usedTabBars();
|
||||
|
||||
|
@ -755,6 +755,8 @@ void tst_QObject::findChildren()
|
||||
op = o.findChild<QObject*>("unnamed", Qt::FindDirectChildrenOnly);
|
||||
QCOMPARE(op, static_cast<QObject *>(0));
|
||||
|
||||
l = o.findChildren<QObject*>(Qt::FindDirectChildrenOnly);
|
||||
QCOMPARE(l.size(), 5);
|
||||
l = o.findChildren<QObject*>(QString(), Qt::FindDirectChildrenOnly);
|
||||
QCOMPARE(l.size(), 5);
|
||||
l = o.findChildren<QObject*>("", Qt::FindDirectChildrenOnly);
|
||||
|
Loading…
Reference in New Issue
Block a user