diff options
| author | Michael Weghorn <[email protected]> | 2025-09-02 15:05:16 +0200 |
|---|---|---|
| committer | Michael Weghorn <[email protected]> | 2025-09-04 19:12:39 +0200 |
| commit | 99a10f4528f617d88518f3834f76b28ae0b0e769 (patch) | |
| tree | 36ef4d22c270b229f3b73af565923e5df3bd1e1a | |
| parent | f257009870f0016d6c48b23e3f41228f4b8158c3 (diff) | |
a11y: Let buddy widget know its label(s)
If a widget is set as the buddy widget of a QLabel,
that label is reported for the widget's QAccessible::Label
relation.
So far, in order to identify labels for which the
widget is set as the buddy, all sibling widgets
were inspected. There was already a comment mentioning
that all objects should ideally be checked, but that
would be too expensive.
Change the approach altogether: Instead of
traversing the widget tree, store all labels for
which the widget is set as the buddy in the widget
itself.
This is more efficient and ensures the relation
is reported correctly for non-siblings as well.
Fixes: QTBUG-139719
Change-Id: I6d517f8727cdde0de38b11d7c6906ecc55da1927
Reviewed-by: MohammadHossein Qanbari <[email protected]>
| -rw-r--r-- | src/widgets/accessible/qaccessiblewidget.cpp | 29 | ||||
| -rw-r--r-- | src/widgets/kernel/qwidget.h | 1 | ||||
| -rw-r--r-- | src/widgets/kernel/qwidget_p.h | 7 | ||||
| -rw-r--r-- | src/widgets/widgets/qlabel.cpp | 11 |
4 files changed, 27 insertions, 21 deletions
diff --git a/src/widgets/accessible/qaccessiblewidget.cpp b/src/widgets/accessible/qaccessiblewidget.cpp index 3d18117dd78..b4adae2e6e6 100644 --- a/src/widgets/accessible/qaccessiblewidget.cpp +++ b/src/widgets/accessible/qaccessiblewidget.cpp @@ -224,29 +224,20 @@ QAccessibleWidget::relations(QAccessible::Relation match /*= QAccessible::AllRel QList<std::pair<QAccessibleInterface *, QAccessible::Relation>> rels; if (match & QAccessible::Label) { const QAccessible::Relation rel = QAccessible::Label; - if (QWidget *parent = widget()->parentWidget()) { #if QT_CONFIG(shortcut) && QT_CONFIG(label) - // first check for all siblings that are labels to us - // ideally we would go through all objects and check, but that - // will be too expensive - const QList<QWidget*> kids = _q_ac_childWidgets(parent); - for (QWidget *kid : kids) { - if (QLabel *labelSibling = qobject_cast<QLabel*>(kid)) { - if (labelSibling->buddy() == widget()) { - QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(labelSibling); - rels.emplace_back(iface, rel); - } - } - } + for (QLabel *label : std::as_const(widget()->d_func()->labels)) { + Q_ASSERT(label); + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(label); + rels.emplace_back(iface, rel); + } #endif #if QT_CONFIG(groupbox) - QGroupBox *groupbox = qobject_cast<QGroupBox*>(parent); - if (groupbox && !groupbox->title().isEmpty()) { - QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(groupbox); - rels.emplace_back(iface, rel); - } -#endif + QGroupBox *groupbox = qobject_cast<QGroupBox *>(widget()->parentWidget()); + if (groupbox && !groupbox->title().isEmpty()) { + QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(groupbox); + rels.emplace_back(iface, rel); } +#endif } if (match & QAccessible::Controlled) { diff --git a/src/widgets/kernel/qwidget.h b/src/widgets/kernel/qwidget.h index 02f328d2956..96565957a00 100644 --- a/src/widgets/kernel/qwidget.h +++ b/src/widgets/kernel/qwidget.h @@ -746,6 +746,7 @@ private: friend class QGuiApplication; friend class QGuiApplicationPrivate; friend class QBaseApplication; + friend class QLabel; friend class QPainter; friend class QPainterPrivate; friend class QPixmap; // for QPixmap::fill() diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 991b932ecb8..ac417178813 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -19,6 +19,9 @@ #include <QtWidgets/private/qtwidgetsglobal_p.h> #include "QtWidgets/qwidget.h" +#if QT_CONFIG(label) +#include <QtWidgets/qlabel.h> +#endif #include "private/qobject_p.h" #include "QtCore/qrect.h" #include "QtCore/qlocale.h" @@ -655,6 +658,10 @@ public: QPaintEngine *extraPaintEngine; mutable const QMetaObject *polished; QGraphicsEffect *graphicsEffect; +#if QT_CONFIG(label) + // labels for which this widget is the buddy widget + QVarLengthArray<QLabel *, 1> labels; +#endif // All widgets are added into the allWidgets set. Once // they receive a window id they are also added to the mapper. // This should just ensure that all widgets are deleted by QApplication diff --git a/src/widgets/widgets/qlabel.cpp b/src/widgets/widgets/qlabel.cpp index 72f299792bb..5cff4485fe3 100644 --- a/src/widgets/widgets/qlabel.cpp +++ b/src/widgets/widgets/qlabel.cpp @@ -187,6 +187,9 @@ QLabel::QLabel(const QString &text, QWidget *parent, Qt::WindowFlags f) QLabel::~QLabel() { Q_D(QLabel); + + if (d->buddy) + d->buddy->d_func()->labels.removeAll(this); d->clearContents(); } @@ -1139,15 +1142,19 @@ void QLabel::setBuddy(QWidget *buddy) { Q_D(QLabel); - if (d->buddy) + if (d->buddy) { QObjectPrivate::disconnect(d->buddy, &QObject::destroyed, d, &QLabelPrivate::buddyDeleted); + d->buddy->d_func()->labels.removeAll(this); + } d->buddy = buddy; - if (buddy) + if (buddy) { + buddy->d_func()->labels.append(this); QObjectPrivate::connect(buddy, &QObject::destroyed, d, &QLabelPrivate::buddyDeleted); + } if (d->isTextLabel) { if (d->shortcutId) |
