Accessibilité des applications QWidget
Introduction
Nous nous concentrerons sur l'interface d'accessibilité de Qt QAccessibleInterface et sur la manière de rendre les applications accessibles.
Accessibilité dans les applications basées sur les QWidgets
Lorsque nous communiquons avec les technologies d'assistance, nous devons décrire l'interface utilisateur de Qt d'une manière qu'ils peuvent comprendre. Les applications Qt utilisent QAccessibleInterface pour exposer des informations sur les éléments individuels de l'interface utilisateur. Actuellement, Qt Widgets prend en charge ses widgets et les parties de widgets, par exemple les poignées des curseurs, mais l'interface pourrait également être mise en œuvre pour n'importe quel site QObject si nécessaire. QAccessible contient des enums qui décrivent l'interface utilisateur. Nous les examinerons au cours du présent document.
La structure de l'interface utilisateur est représentée sous la forme d'un arbre de sous-classes QAccessibleInterface. Il s'agit souvent d'un miroir de la hiérarchie des QWidgets qui composent l'interface utilisateur de l'application.
Les serveurs informent les clients, par l'intermédiaire de updateAccessibility(), des modifications apportées aux objets en envoyant des événements, et les clients s'enregistrent pour recevoir ces événements. Les événements disponibles sont définis par l'énumération QAccessible::Event. Les clients peuvent ensuite demander l'objet qui a généré l'événement par l'intermédiaire de QAccessible::queryAccessibleInterface().
Les membres et les enums de QAccessible sont utilisés pour décrire les objets accessibles :
- Role: Décrit le rôle de l'objet dans l'interface utilisateur, par exemple s'il s'agit d'une fenêtre, d'un éditeur de texte ou d'une cellule dans un tableau.
- Relation: Décrit la relation entre les objets dans la hiérarchie des objets.
- State: Les objets peuvent se trouver dans un certain nombre d'états différents. Les objets peuvent se trouver dans un certain nombre d'états différents, par exemple si l'objet est désactivé, s'il a le focus ou s'il fournit un menu contextuel.
Les clients ont également la possibilité d'obtenir le contenu des objets, par exemple le texte d'un bouton ; l'objet fournit des chaînes définies par l'énumération QAccessible::Text, qui donnent des informations sur le contenu.
L'arbre des objets accessibles
Comme nous l'avons mentionné, une structure arborescente est construite à partir des objets accessibles d'une application. En naviguant dans l'arbre, les clients peuvent accéder à tous les éléments de l'interface utilisateur. Les relations entre les objets donnent aux clients des informations sur l'interface utilisateur. Par exemple, la poignée d'un curseur est un enfant du curseur auquel elle appartient. QAccessible::Relation décrit les différentes relations que les clients peuvent demander aux objets.
Notez qu'il n'y a pas de correspondance directe entre l'arbre Qt QObject et l'arbre des objets accessibles. Par exemple, les poignées des barres de défilement sont des objets accessibles mais ne sont pas des widgets ou des objets dans Qt.
Les AT-Clients ont accès à l'arbre des objets accessibles par l'intermédiaire de l'objet racine de l'arbre, qui est le QApplication. Ils peuvent naviguer dans l'arbre avec les fonctions QAccessibleInterface::parent(), QAccessibleInterface::childCount() et QAccessibleInterface::child().
Qt Widgets fournit des interfaces accessibles pour ses widgets et pour les contrôles Qt Quick. Les interfaces de toute sous-classe de QObject peuvent être demandées via QAccessible::queryInterface(). Une implémentation par défaut est fournie si une interface plus spécialisée n'est pas définie. Un AT-Client ne peut pas acquérir une interface pour les objets accessibles qui n'ont pas d'équivalent QObject, par exemple les poignées des barres de défilement, mais ils apparaissent comme des objets normaux à travers les interfaces des objets accessibles parents, par exemple, vous pouvez interroger leurs relations avec QAccessibleInterface::relations().
Pour illustrer notre propos, nous présentons une image d'un arbre d'objets accessibles. Sous l'arbre se trouve un tableau contenant des exemples de relations entre objets.

Les étiquettes sont, dans l'ordre décroissant, le nom de la classe QAccessibleInterface, le widget pour lequel une interface est fournie et le Role de l'objet. La position, la page gauche et la page droite correspondent respectivement à la poignée du curseur, à la rainure gauche du curseur et à la rainure droite du curseur. Ces objets accessibles n'ont pas d'équivalent QObject.
| Objet source | Objet cible | Relation |
|---|---|---|
| Curseur | Indicateur | Contrôleur |
| Indicateur | Curseur | Contrôlé |
| Curseur | Application | Ancêtre |
| Application | Curseur | Enfant |
| Bouton poussoir | Indicateur | Frère ou sœur |
Les fonctions statiques de QAccessible
L'accessibilité est gérée par les fonctions statiques de QAccessible, que nous examinerons prochainement. Elles produisent les interfaces QAccessible, construisent l'arbre d'objets et initient la connexion avec MSAA ou les autres technologies spécifiques à la plate-forme. Si vous souhaitez uniquement apprendre à rendre votre application accessible, vous pouvez sans crainte passer cette section à la mise en œuvre de l'accessibilité.
La communication entre les clients et le serveur est initiée lorsque setRootObject() est appelé. Cela se fait lors de l'instanciation de l'instance QApplication et vous ne devriez pas avoir à le faire vous-même.
Lorsqu'une instance QObject appelle updateAccessibility(), les clients qui écoutent les événements sont informés du changement. La fonction est utilisée pour envoyer des événements à la technologie d'assistance, et events accessible est envoyé par updateAccessibility().
queryAccessibleInterface() renvoie des interfaces accessibles pour QObjects. Tous les widgets de Qt Widgets fournissent des interfaces ; si vous avez besoin d'interfaces pour contrôler le comportement d'autres sous-classes QObject, vous devez implémenter les interfaces vous-même, bien que la classe de commodité QAccessibleObject implémente certaines parties de la fonctionnalité pour vous.
La fabrique qui produit les interfaces d'accessibilité pour les QObjects est une fonction de type QAccessible::InterfaceFactory. Il est possible d'installer plusieurs fabriques. La dernière fabrique installée sera la première à être sollicitée pour des interfaces. queryAccessibleInterface() utilise les fabriques pour créer des interfaces pour QObjects. Normalement, vous n'avez pas à vous préoccuper des fabriques car vous pouvez implémenter des plugins qui produisent des interfaces. Nous donnerons plus loin des exemples des deux approches.
Mise en œuvre de l'accessibilité
Pour fournir un support d'accessibilité à un widget ou à un autre élément d'interface utilisateur, vous devez implémenter l'interface QAccessibleInterface et la distribuer dans un QAccessiblePlugin. Il est également possible de compiler l'interface dans l'application et de fournir un QAccessible::InterfaceFactory pour celle-ci. La fabrique peut être utilisée si vous créez des liens statiques ou si vous ne souhaitez pas la complexité supplémentaire des plugins. Cela peut être un avantage si, par exemple, vous livrez une bibliothèque tierce.
Tous les widgets et autres éléments de l'interface utilisateur doivent avoir des interfaces et des plugins. Si vous souhaitez que votre application prenne en charge l'accessibilité, vous devrez tenir compte des éléments suivants :
- Qt Widgets met déjà en œuvre l'accessibilité pour ses propres widgets. Nous vous recommandons donc d'utiliser les Qt Widgets dans la mesure du possible.
- Un site QAccessibleInterface doit être mis en œuvre pour chaque élément que vous souhaitez mettre à la disposition des clients accessibles.
- Vous devez envoyer des événements d'accessibilité à partir des éléments d'interface utilisateur personnalisés que vous mettez en œuvre.
En général, il est recommandé d'être quelque peu familier avec MSAA, pour lequel le support d'accessibilité de Qt a été construit à l'origine. Vous devriez également étudier les valeurs enum de QAccessible, qui décrivent les rôles, les actions, les relations et les événements que vous devez prendre en compte.
Notez que vous pouvez examiner comment les widgets de Qt Widgets implémentent leur accessibilité. L'un des principaux problèmes de la norme MSAA est que les interfaces sont souvent mises en œuvre de manière incohérente. Cela complique la vie des clients et les amène souvent à deviner les fonctionnalités des objets.
Il est possible d'implémenter des interfaces en héritant de QAccessibleInterface et en implémentant ses fonctions virtuelles pures. Dans la pratique, cependant, il est généralement préférable d'hériter de QAccessibleObject ou QAccessibleWidget, qui implémentent une partie de la fonctionnalité à votre place. Dans la section suivante, nous verrons un exemple d'implémentation de l'accessibilité pour un widget en héritant de la classe QAccessibleWidget.
Les classes de commodité QAccessibleObject et QAccessibleWidget
Lors de la mise en œuvre d'une interface d'accessibilité pour les widgets, on hérite généralement de la classe QAccessibleWidget, qui est une classe de commodité pour les widgets. Une autre classe de commodité disponible, héritée de QAccessibleWidget, est QAccessibleObject, qui implémente une partie de l'interface pour les QObjects.
Le site QAccessibleWidget offre les fonctionnalités suivantes :
- Elle gère la navigation dans l'arbre et les tests de collision des objets.
- Il gère les événements, les rôles et les actions qui sont communs à tous les QWidget.
- Il gère les actions et les méthodes qui peuvent être exécutées sur tous les widgets.
- Il calcule les rectangles de délimitation avec rect().
- Il donne à text() des chaînes appropriées pour un widget générique.
- Il définit les states qui sont communs à tous les widgets.
Exemple de QAccessibleWidget
Au lieu de créer un widget personnalisé et d'implémenter une interface pour lui, nous allons montrer comment l'accessibilité est implémentée pour l'un des widgets standard de Qt Widgets : QSlider. L'interface accessible, QAccessibleSlider, hérite de QAccessibleAbstractSlider, qui hérite à son tour de QAccessibleWidget. Il n'est pas nécessaire d'examiner la classe QAccessibleAbstractSlider pour lire cette section. Si vous voulez jeter un coup d'œil, le code de toutes les interfaces accessibles de Qt se trouve dans qtbase/src/widgets/accessible. Voici le constructeur de QAccessibleSlider :
QAccessibleSlider::QAccessibleSlider(QWidget *w) : QAccessibleAbstractSlider(w) { Q_ASSERT(slider()); addControllingSignal(QLatin1String("valueChanged(int)")); }
Le curseur est un contrôle complexe qui fonctionne comme Controller pour ses enfants accessibles. Cette relation doit être connue par l'interface (pour parent(), child() et relations()). Cela peut se faire à l'aide d'un signal de contrôle, qui est un mécanisme fourni par QAccessibleWidget. Nous le faisons dans le constructeur :
Le choix du signal présenté n'est pas important ; les mêmes principes s'appliquent à tous les signaux déclarés de cette manière. Notez que nous utilisons QLatin1String pour nous assurer que le nom du signal est correctement spécifié.
Lorsqu'un objet accessible est modifié d'une manière dont les utilisateurs doivent être informés, il en informe les clients en leur envoyant un événement via l'interface accessible. C'est ainsi que QSlider appelle updateAccessibility() pour indiquer que sa valeur a changé :
void QAbstractSlider::setValue(int value) ... QAccessibleValueChangeEvent event(this, d->value); QAccessible::updateAccessibility(&event); ... }
Notez que l'appel est effectué après que la valeur du curseur a changé, car les clients peuvent demander la nouvelle valeur immédiatement après avoir reçu l'événement.
L'interface doit être capable de calculer les rectangles de délimitation d'elle-même et de tous les enfants qui ne fournissent pas d'interface propre. L'interface QAccessibleSlider a trois enfants de ce type, identifiés par l'enum privé SliderElements, qui a les valeurs suivantes : PageLeft (le rectangle à gauche de la poignée du curseur), PageRight (le rectangle à droite de la poignée) et Position (la poignée du curseur). Voici l'implémentation de rect() :
QRect QAccessibleSlider::rect(int child) const { ... switch (child) { case PageLeft: if (slider()->orientation() == Qt::Vertical) rect = QRect(0, 0, slider()->width(), srect.y()); else rect = QRect(0, 0, srect.x(), slider()->height()); break; case Position: rect = srect; break; case PageRight: if (slider()->orientation() == Qt::Vertical) rect = QRect(0, srect.y() + srect.height(), slider()->width(), slider()->height()- srect.y() - srect.height()); else rect = QRect(srect.x() + srect.width(), 0, slider()->width() - srect.x() - srect.width(), slider()->height()); break; default: return QAccessibleAbstractSlider::rect(child); } ...
La première partie de la fonction, que nous avons omise, utilise la valeur courante de style pour calculer le rectangle de délimitation de la poignée du curseur ; elle est stockée dans srect. Notez que l'enfant 0, couvert par défaut dans le code ci-dessus, est le curseur lui-même, de sorte que nous pouvons simplement renvoyer le rectangle de délimitation de QSlider obtenu à partir de la superclasse, qui est en fait la valeur obtenue à partir de QAccessibleWidget::rect().
QPoint tp = slider()->mapToGlobal(QPoint(0,0)); return QRect(tp.x() + rect.x(), tp.y() + rect.y(), rect.width(), rect.height()); }
Avant que le rectangle ne soit renvoyé, il doit être converti en coordonnées d'écran.
Le QAccessibleSlider doit réimplémenter QAccessibleInterface::childCount() puisqu'il gère les enfants sans interface.
La fonction text() renvoie les chaînes QAccessible::Text du curseur :
QString QAccessibleSlider::text(Text t, int child) const { if (!slider()->isVisible()) return QString(); switch (t) { case Value: if (!child || child == 2) return QString::number(slider()->value()); return QString(); case Name: switch (child) { case PageLeft: return slider()->orientation() == Qt::Horizontal ? QSlider::tr("Page left") : QSlider::tr("Page up"); case Position: return QSlider::tr("Position"); case PageRight: return slider()->orientation() == Qt::Horizontal ? QSlider::tr("Page right") : QSlider::tr("Page down"); } break; default: break; } return QAccessibleAbstractSlider::text(t, child); }
La fonction slider() renvoie un pointeur sur l'interface QSlider. Certaines valeurs sont laissées à l'implémentation de la superclasse. Toutes les valeurs ne sont pas appropriées pour tous les objets accessibles, comme vous pouvez le voir dans le cas de QAccessible::Value. Vous devriez simplement renvoyer une chaîne vide pour les valeurs pour lesquelles aucun texte pertinent ne peut être fourni.
L'implémentation de la fonction role() est simple :
QAccessible::Role QAccessibleSlider::role(int child) const { switch (child) { case PageLeft: case PageRight: return PushButton; case Position: return Indicator; default: return Slider; } }
La fonction role doit être réimplémentée par tous les objets et décrit leur rôle et celui des enfants qui ne fournissent pas d'interfaces accessibles propres.
Ensuite, l'interface accessible doit renvoyer le site states dans lequel le curseur peut se trouver. Nous examinons certaines parties de l'implémentation de state() pour montrer comment quelques états sont gérés :
QAccessible::State QAccessibleSlider::state(int child) const { const State parentState = QAccessibleAbstractSlider::state(0); ... switch (child) { case PageLeft: if (slider->value() <= slider->minimum()) state |= Unavailable; break; case PageRight: if (slider->value() >= slider->maximum()) state |= Unavailable; break; case Position: default: break; } return state; }
L'implémentation de la superclasse state() utilise l'implémentation QAccessibleInterface::state(). Nous devons simplement désactiver les boutons si le curseur est à son minimum ou à son maximum.
Nous avons maintenant exposé aux clients les informations dont nous disposons sur le curseur. Pour que les clients puissent modifier le curseur - par exemple, pour changer sa valeur - nous devons fournir des informations sur les actions qui peuvent être effectuées et les exécuter à la demande. Nous abordons ce point dans la section suivante.
Traitement des demandes d'action des clients
Les applications peuvent exposer des actions qui peuvent être invoquées par le client. Pour prendre en charge les actions dans un objet, il faut hériter de la propriété QAccessibleActionInterface.
Les éléments interactifs doivent présenter des fonctionnalités déclenchées par l'interaction de la souris, par exemple. Un bouton doit, par exemple, mettre en œuvre une action de clic.
La définition du focus est une autre action qui doit être mise en œuvre pour les widgets qui acceptent de recevoir le focus.
Vous devez réimplémenter actionNames() pour renvoyer une liste de toutes les actions prises en charge par l'objet. Cette liste ne doit pas être localisée.
Il existe deux fonctions qui donnent des informations sur les actions qui doivent renvoyer des chaînes localisées : localizedActionName() et localizedActionDescription(). Ces fonctions peuvent être utilisées par le client pour présenter les actions à l'utilisateur. En général, le nom doit être concis et ne comporter qu'un seul mot, comme "press".
Il existe une liste de noms d'actions et de localisations standard qui doivent être utilisés lorsque l'action est adaptée. Cela permet aux clients de comprendre plus facilement la sémantique, et Qt essaiera de les exposer correctement sur les différentes plates-formes.
Bien entendu, l'action doit également pouvoir être déclenchée. doAction() doit invoquer l'action telle qu'elle est annoncée par son nom et sa description.
Pour voir des exemples de mise en œuvre d'actions et de méthodes, vous pouvez examiner les mises en œuvre des widgets standard de Qt, tels que QAccessiblePushButton.
Mise en œuvre de plugins accessibles
Dans cette section, nous expliquerons la procédure d'implémentation de plugins accessibles pour vos interfaces. Un plugin est une classe stockée dans une bibliothèque partagée qui peut être chargée au moment de l'exécution. Il est pratique de distribuer les interfaces sous forme de plugins, car elles ne seront chargées qu'en cas de besoin.
La création d'un plugin accessible se fait en héritant de QAccessiblePlugin, en définissant les noms de classe supportés dans la description JSON du plugin et en réimplémentant create() à partir de QAccessiblePlugin. Le fichier .pro doit être modifié pour utiliser le modèle de plugin, et la bibliothèque contenant le plugin doit être placée sur un chemin où Qt recherche des plugins accessibles.
Nous allons passer en revue l'implémentation de SliderPlugin, qui est un plugin accessible produisant l'interface QAccessibleSlider de l'exemple QAccessibleWidget. Nous commençons par la fonction key():
QStringList SliderPlugin::keys() const { return QStringList() << QLatin1String("QSlider"); }
Nous devons simplement renvoyer le nom de la classe de l'interface unique pour laquelle notre plugin peut créer une interface accessible. Un plugin peut supporter n'importe quel nombre de classes ; il suffit d'ajouter d'autres noms de classes à la liste de chaînes. Nous passons à la fonction create():
QAccessibleInterface *SliderPlugin::create(const QString &classname, QObject *object) { QAccessibleInterface *interface = 0; if (classname == QLatin1String("QSlider") && object && object->isWidgetType()) interface = new QAccessibleSlider(static_cast<QWidget *>(object)); return interface; }
Nous vérifions si l'interface demandée concerne QSlider; si c'est le cas, nous créons et renvoyons une interface pour cette interface. Notez que object sera toujours une instance de classname. Vous devez renvoyer 0 si vous ne supportez pas la classe. updateAccessibility() vérifie les plugins d'accessibilité disponibles jusqu'à ce qu'il en trouve un qui ne renvoie pas 0.
Enfin, vous devez inclure des macros dans le fichier cpp :
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.Accessibility.SliderPlugin" FILE "slider.json")La macro Q_PLUGIN_METADATA exporte le plugin de la classe SliderPlugin dans la bibliothèque acc_sliderplugin. Le premier argument est l'IID du plugin et le second est un fichier json facultatif qui contient des informations sur les métadonnées du plugin. Pour plus d'informations sur les plugins, vous pouvez consulter le document de présentation des plugins.
Il n'est pas nécessaire que le plugin soit lié statiquement ou dynamiquement à l'application.
Implémentation de fabriques d'interfaces
Si vous ne souhaitez pas fournir de plugins pour vos interfaces d'accessibilité, vous pouvez utiliser une fabrique d'interfaces (QAccessible::InterfaceFactory), qui est la méthode recommandée pour fournir des interfaces accessibles dans une application liée statiquement.
Une fabrique est un pointeur de fonction pour une fonction qui prend les mêmes paramètres que QAccessiblePlugin's create() - un QString et un QObject. Elle fonctionne également de la même manière. Vous installez la fabrique avec la fonction installFactory(). Nous donnons un exemple de création d'une fabrique pour l'interface QAccessibleSlider:
QAccessibleInterface *sliderFactory(const QString &classname, QObject *object) { QAccessibleInterface *interface = 0; if (classname == QLatin1String("QSlider") && object && object->isWidgetType()) interface = new QAccessibleSlider(static_cast<QWidget *>(object)); return interface; } int main(int argc, char *argv[]) { QApplication app(argc, argv); QAccessible::installFactory(sliderFactory); ... }
Classes apparentées
Permet l'accessibilité des éléments QML | |
Enums et fonctions statiques liées à l'accessibilité | |
Implémente la prise en charge des actions invocables dans l'interface | |
Utilisée pour demander l'annonce d'un message donné par des technologies d'assistance | |
Prise en charge des attributs de rapport pour un objet accessible | |
Prise en charge des objets dont le texte est modifiable | |
Classe de base pour les notifications d'accessibilité | |
Définit une interface qui expose des informations sur les objets accessibles | |
Implémente des parties de la QAccessibleInterface pour les QObjects | |
Classe de base abstraite pour les plugins fournissant des informations sur l'accessibilité des éléments de l'interface utilisateur | |
Implémente un support pour la gestion de la sélection | |
Indique au cadre d'accessibilité que l'état d'un objet a changé. | |
Prend en charge l'interface IAccessibleTable2 Cell | |
Met en œuvre la prise en charge de l'interface IAccessibleTable2 | |
Signifie un changement dans un tableau, une liste ou un arbre où des cellules sont ajoutées ou supprimées. Si la modification concerne un certain nombre de lignes, firstColumn et lastColumn renvoient -1. De même, pour les colonnes, les fonctions de ligne peuvent renvoyer -1. | |
Notifie les mouvements du curseur | |
Notifie l'insertion de texte | |
Prise en charge de la gestion du texte | |
Notifie la suppression de texte | |
Signale un changement dans la sélection de texte d'un objet | |
Notifie les changements de texte. Cet événement concerne les accès qui prennent en charge le texte éditable, comme les éditions de lignes. Cet événement se produit par exemple lorsqu'une partie du texte sélectionné est remplacée par le collage d'un nouveau texte ou dans le mode de remplacement des éditeurs. | |
Décrit un changement de valeur pour un objet accessible. | |
Mise en place d'un support pour les objets qui manipulent une valeur | |
Implémente la QAccessibleInterface pour les QWidgets |
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.