summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Weghorn <[email protected]>2025-09-02 15:05:16 +0200
committerMichael Weghorn <[email protected]>2025-09-04 19:12:39 +0200
commit99a10f4528f617d88518f3834f76b28ae0b0e769 (patch)
tree36ef4d22c270b229f3b73af565923e5df3bd1e1a
parentf257009870f0016d6c48b23e3f41228f4b8158c3 (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.cpp29
-rw-r--r--src/widgets/kernel/qwidget.h1
-rw-r--r--src/widgets/kernel/qwidget_p.h7
-rw-r--r--src/widgets/widgets/qlabel.cpp11
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)