En esta página

Accesibilidad para aplicaciones QWidget

Introducción

Nos centraremos en la interfaz de accesibilidad de Qt QAccessibleInterface y en cómo hacer que las aplicaciones sean accesibles.

Accesibilidad en aplicaciones basadas en QWidget

Cuando nos comunicamos con las tecnologías de asistencia, necesitamos describir la interfaz de usuario de Qt de forma que puedan entenderla. Las aplicaciones Qt utilizan QAccessibleInterface para exponer información sobre los elementos individuales de la interfaz de usuario. Actualmente, Qt proporciona soporte para sus widgets y partes de widgets, por ejemplo, controles deslizantes, pero la interfaz también podría implementarse para cualquier QObject si fuera necesario. QAccessible contiene enums que describen la interfaz de usuario. Examinaremos los enums a lo largo de este documento.

La estructura de la interfaz de usuario se representa como un árbol de QAccessibleInterface subclases. Esto es a menudo un espejo de la jerarquía de QWidgets que componen la UI de la aplicación.

Los servidores notifican a los clientes a través de updateAccessibility() sobre cambios en los objetos enviando eventos, y los clientes se registran para recibir los eventos. Los eventos disponibles están definidos por el enum QAccessible::Event. Los clientes pueden entonces consultar el objeto que generó el evento a través de QAccessible::queryAccessibleInterface().

Los miembros y enums de QAccessible se utilizan para describir objetos accesibles:

  • Role: Describe el papel que desempeña el objeto en la interfaz de usuario, por ejemplo, si es una ventana, una edición de texto o una celda de una tabla.
  • Relation: Describe la relación entre objetos en la jerarquía de objetos.
  • State: Los objetos pueden encontrarse en diferentes estados. Ejemplos de estados son si el objeto está desactivado, si tiene foco o si proporciona un menú emergente.

Los clientes también tienen algunas posibilidades de obtener el contenido de los objetos, por ejemplo, el texto de un botón; el objeto proporciona cadenas definidas por el enum QAccessible::Text, que dan información sobre el contenido.

El árbol de objetos accesible

Como ya se ha mencionado, se construye una estructura de árbol a partir de los objetos accesibles de una aplicación. Navegando por el árbol, los clientes pueden acceder a todos los elementos de la interfaz de usuario. Las relaciones entre objetos proporcionan a los clientes información sobre la interfaz de usuario. Por ejemplo, un control deslizante es hijo del control deslizante al que pertenece. QAccessible::Relation describe las distintas relaciones que los clientes pueden solicitar a los objetos.

Ten en cuenta que no hay una correspondencia directa entre el árbol Qt QObject y el árbol de objetos accesibles. Por ejemplo, los manejadores de la barra de desplazamiento son objetos accesibles pero no son widgets u objetos en Qt.

Los clientes AT tienen acceso al árbol de objetos accesibles a través del objeto raíz del árbol, que es QApplication. Pueden navegar por el árbol con las funciones QAccessibleInterface::parent(), QAccessibleInterface::childCount() y QAccessibleInterface::child().

Qt proporciona interfaces accesibles para sus widgets y para Qt Quick Controls. Las interfaces para cualquier subclase de QObject pueden solicitarse a través de QAccessible::queryInterface(). Se proporciona una implementación por defecto si no se define una interfaz más especializada. Un AT-Client no puede adquirir una interfaz para objetos accesibles que no tengan una equivalente QObject, por ejemplo, los tiradores de la barra de desplazamiento, pero aparecen como objetos normales a través de interfaces de objetos accesibles padres, por ejemplo, se pueden consultar sus relaciones con QAccessibleInterface::relations().

Para ilustrarlo, presentamos una imagen de un árbol de objetos accesibles. Debajo del árbol hay una tabla con ejemplos de relaciones entre objetos.

Las etiquetas en orden descendente son: el nombre de la clase QAccessibleInterface, el widget para el que se proporciona una interfaz y el Role del objeto. Posición, PáginaIzquierda y PáginaDerecha corresponden al tirador de la corredera, a la ranura de la corredera a la izquierda y a la ranura de la corredera a la derecha, respectivamente. Estos objetos accesibles no tienen un equivalente QObject.

Objeto OrigenObjeto DestinoRelación
DeslizadorIndicadorControlador
IndicadorDeslizadorControlado
DeslizadorAplicaciónAncestro
AplicaciónDeslizadorHijo
PulsadorIndicadorHermano

Las funciones estáticas de QAccessible

La accesibilidad es gestionada por las funciones estáticas de QAccessible, que examinaremos en breve. Producen interfaces QAccessible, construyen el árbol de objetos e inician la conexión con MSAA o con otras tecnologías específicas de la plataforma. Si sólo estás interesado en aprender cómo hacer tu aplicación accesible, puedes saltarte con seguridad esta sección para Implementar la Accesibilidad.

La comunicación entre los clientes y el servidor se inicia cuando se llama a setRootObject(). Esto se hace cuando se instancia la instancia QApplication y no deberías tener que hacerlo tú mismo.

Cuando un QObject llama a updateAccessibility(), los clientes que están escuchando eventos son notificados del cambio. La función se utiliza para enviar eventos a la tecnología de asistencia, y los events accesibles son enviados por updateAccessibility().

queryAccessibleInterface() devuelve interfaces accesibles para QObjects. Todos los widgets en Qt proporcionan interfaces; si necesitas interfaces para controlar el comportamiento de otras subclases de QObject, debes implementar las interfaces tú mismo, aunque la clase de conveniencia QAccessibleObject implementa partes de la funcionalidad por ti.

La fábrica que produce interfaces de accesibilidad para QObjects es una función de tipo QAccessible::InterfaceFactory. Es posible tener varias fábricas instaladas. La última fábrica instalada será la primera a la que se le pidan interfaces. queryAccessibleInterface() utiliza las fábricas para crear interfaces para QObjects. Normalmente, no necesitas preocuparte por las fábricas porque puedes implementar plugins que produzcan interfaces. Más adelante daremos ejemplos de ambos enfoques.

Implementación de la accesibilidad

Para proporcionar soporte de accesibilidad a un widget u otro elemento de la interfaz de usuario, es necesario implementar la QAccessibleInterface y distribuirla en un QAccessiblePlugin. También es posible compilar la interfaz en la aplicación y proporcionar un QAccessible::InterfaceFactory para ella. La fábrica puede utilizarse si enlazas estáticamente o no quieres la complejidad añadida de los plugins. Esto puede ser una ventaja si, por ejemplo, estás entregando una librería de terceros.

Todos los widgets y otros elementos de la interfaz de usuario deben tener interfaces y plugins. Si quieres que tu aplicación soporte accesibilidad, tendrás que tener en cuenta lo siguiente:

  • Qt ya implementa la accesibilidad para sus propios widgets. Por tanto, te recomendamos que utilices los Qt Widgets siempre que sea posible.
  • Es necesario implementar un QAccessibleInterface para cada elemento que quieras poner a disposición de los clientes de accesibilidad.
  • Es necesario enviar eventos de accesibilidad desde los elementos de interfaz de usuario personalizados que se implementen.

En general, se recomienda que estés familiarizado con MSAA, para el que se construyó originalmente el soporte de accesibilidad de Qt. También deberías estudiar los valores enum de QAccessible, que describen los roles, acciones, relaciones y eventos que necesitas tener en cuenta.

Ten en cuenta que puedes examinar cómo implementan su accesibilidad los widgets de Qt. Uno de los principales problemas del estándar MSAA es que las interfaces se implementan a menudo de forma incoherente. Esto hace la vida difícil a los clientes y a menudo conduce a conjeturas sobre la funcionalidad de los objetos.

Es posible implementar interfaces heredando QAccessibleInterface e implementando sus funciones virtuales puras. En la práctica, sin embargo, suele ser preferible heredar QAccessibleObject o QAccessibleWidget, que implementan parte de la funcionalidad por ti. En la siguiente sección, veremos un ejemplo de implementación de accesibilidad para un widget heredando la clase QAccessibleWidget.

Las clases de conveniencia QAccessibleObject y QAccessibleWidget

Cuando se implementa una interfaz de accesibilidad para widgets, lo normal es heredar de QAccessibleWidget, que es una clase de conveniencia para widgets. Otra clase de conveniencia disponible, que hereda QAccessibleWidget, es QAccessibleObject, que implementa parte de la interfaz para QObjects.

QAccessibleWidget proporciona la siguiente funcionalidad:

  • Maneja la navegación del árbol y la prueba de acierto de los objetos.
  • Maneja eventos, roles y acciones que son comunes para todos los QWidgets.
  • Maneja acciones y métodos que se pueden realizar en todos los widgets.
  • Calcula rectángulos delimitadores con rect().
  • Proporciona text() cadenas que son apropiadas para un widget genérico.
  • Establece los states que son comunes para todos los widgets.

Ejemplo de QAccessibleWidget

En lugar de crear un widget personalizado e implementar una interfaz para él, mostraremos cómo se implementa la accesibilidad para uno de los widgets estándar de Qt: QSlider. La interfaz accesible, QAccessibleSlider, hereda de QAccessibleAbstractSlider, que a su vez hereda de QAccessibleWidget. No necesitas examinar la clase QAccessibleAbstractSlider para leer esta sección. Si quieres echar un vistazo, el código de todas las interfaces accesibles de Qt se encuentra en qtbase/src/widgets/accessible. Aquí está el constructor de QAccessibleSlider:

QAccessibleSlider::QAccessibleSlider(QWidget *w)
: QAccessibleAbstractSlider(w)
{
    Q_ASSERT(slider());
    addControllingSignal(QLatin1String("valueChanged(int)"));
}

El deslizador es un control complejo que funciona como Controller para sus hijos accesibles. Esta relación debe ser conocida por la interfaz (para parent(), child() y relations()). Esto puede hacerse utilizando una señal de control, que es un mecanismo proporcionado por QAccessibleWidget. Lo hacemos en el constructor:

La elección de la señal mostrada no es importante; los mismos principios se aplican a todas las señales que se declaran de esta manera. Nótese que utilizamos QLatin1String para asegurarnos de que el nombre de la señal está correctamente especificado.

Cuando un objeto accesible cambia de una forma que los usuarios necesitan conocer, notifica el cambio a los clientes enviándoles un evento a través de la interfaz accesible. Así es como QSlider llama a updateAccessibility() para indicar que su valor ha cambiado:

void QAbstractSlider::setValue(int value)
    ...
    QAccessibleValueChangeEvent event(this, d->value);
    QAccessible::updateAccessibility(&event);
    ...
}

Nótese que la llamada se realiza después de que el valor del deslizador haya cambiado porque los clientes pueden consultar el nuevo valor inmediatamente después de recibir el evento.

La interfaz debe ser capaz de calcular los rectángulos delimitadores de sí misma y de cualquier hijo que no proporcione una interfaz propia. QAccessibleSlider tiene tres hijos identificados por el enum privado, SliderElements, que tiene los siguientes valores: PageLeft (el rectángulo a la izquierda del control deslizante), PageRight (el rectángulo a la derecha del control deslizante) y Position (el control deslizante). He aquí la implementación 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 primera parte de la función, que hemos omitido, utiliza el style actual para calcular el rectángulo delimitador del tirador deslizante; se almacena en srect. Observe que el hijo 0, cubierto en el caso por defecto en el código anterior, es el propio deslizador, por lo que podemos simplemente devolver el rectángulo delimitador QSlider obtenido de la superclase, que es efectivamente el valor obtenido de QAccessibleWidget::rect().

    QPoint tp = slider()->mapToGlobal(QPoint(0,0));
    return QRect(tp.x() + rect.x(), tp.y() + rect.y(), rect.width(), rect.height());
}

Antes de que el rectángulo sea devuelto debe ser mapeado a coordenadas de pantalla.

El QAccessibleSlider debe reimplementar QAccessibleInterface::childCount() ya que maneja hijos sin interfaces.

La función text() devuelve las cadenas QAccessible::Text para el deslizador:

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 función slider() devuelve un puntero a la interfaz QSlider. Algunos valores se dejan para la implementación de la superclase. No todos los valores son apropiados para todos los objetos accesibles, como se puede ver para el caso QAccessible::Value. Debería simplemente devolver una cadena vacía para aquellos valores en los que no se puede proporcionar un texto relevante.

La implementación de la función role() es sencilla:

QAccessible::Role QAccessibleSlider::role(int child) const
{
    switch (child) {
    case PageLeft:
    case PageRight:
        return PushButton;
    case Position:
        return Indicator;
    default:
        return Slider;
    }
}

La función role debe ser reimplementada por todos los objetos y describe el rol de ellos mismos y de los hijos que no proporcionan interfaces accesibles propias.

A continuación, la interfaz accesible debe devolver el states en el que puede estar el deslizador. Veremos partes de la implementación de state() para mostrar cómo se manejan algunos de los estados:

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;
}

La implementación de la superclase de state(), utiliza la implementación de QAccessibleInterface::state(). Simplemente necesitamos desactivar los botones si el deslizador está en su mínimo o máximo.

Ahora hemos expuesto la información que tenemos sobre el deslizador a los clientes. Para que los clientes puedan alterar el deslizador -por ejemplo, para cambiar su valor- debemos proporcionar información sobre las acciones que se pueden realizar y llevarlas a cabo bajo petición. Este tema se trata en la siguiente sección.

Gestión de las solicitudes de acciones de los clientes

Las aplicaciones pueden exponer acciones, que pueden ser invocadas por el cliente. Para soportar acciones en un objeto, hereda el QAccessibleActionInterface.

Los elementos interactivos deben exponer funcionalidades activadas por la interacción del ratón, por ejemplo. Un botón, por ejemplo, debería implementar una acción de clic.

Establecer el foco es otra acción que debería implementarse para los widgets que aceptan recibir el foco.

Necesitas reimplementar actionNames() para devolver una lista de todas las acciones que soporta el objeto. Esta lista no debe ser localizada.

Hay dos funciones que dan información sobre las acciones que deben devolver cadenas localizadas: localizedActionName() y localizedActionDescription(). Estas funciones pueden ser utilizadas por el cliente para presentar las acciones al usuario. En general, el nombre debe ser conciso y constar de una sola palabra, como "pulsar".

Existe una lista de nombres de acciones y localizaciones estándar que deben utilizarse cuando la acción encaje. Esto hace que sea más fácil para los clientes entender la semántica, y Qt intentará exponerlas correctamente en las diferentes plataformas.

Por supuesto, la acción también necesita una forma de ser disparada. doAction() debería invocar la acción tal y como se anuncia por nombre y descripción.

Para ver ejemplos de cómo implementar acciones y métodos, puedes examinar las implementaciones de los widgets estándar de Qt, como QAccessiblePushButton.

Implementación de plugins accesibles

En esta sección explicaremos el procedimiento de implementación de plugins accesibles para tus interfaces. Un plugin es una clase almacenada en una librería compartida que puede ser cargada en tiempo de ejecución. Es conveniente distribuir las interfaces como plugins, ya que sólo se cargarán cuando sea necesario.

La creación de un plugin accesible se consigue heredando QAccessiblePlugin, definiendo los nombres de las clases soportadas en la descripción JSON del plugin y reimplementando create() desde QAccessiblePlugin. El archivo .pro debe ser alterado para usar la plantilla del plugin, y la librería que contiene el plugin debe ser colocada en una ruta donde Qt busque plugins accesibles.

Revisaremos la implementación de SliderPlugin, que es un plugin accesible que produce la interfaz QAccessibleSlider del ejemplo QAccessibleWidget. Comenzamos con la función key():

QStringList SliderPlugin::keys() const
{
    return QStringList() << QLatin1String("QSlider");
}

Simplemente necesitamos devolver el nombre de la clase de la única interfaz para la que nuestro plugin puede crear una interfaz accesible. Un plugin puede soportar cualquier número de clases; simplemente añade más nombres de clases a la lista de cadenas. Pasamos a la función 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;
}

Comprobamos si la interfaz solicitada es para QSlider; si lo es, creamos y devolvemos una interfaz para ella. Nótese que object siempre será una instancia de classname. Debe devolver 0 si no soporta la clase. updateAccessibility() comprueba con los plugins de accesibilidad disponibles hasta que encuentra uno que no devuelve 0.

Finalmente, necesitas incluir macros en el archivo cpp:

    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.Accessibility.SliderPlugin" FILE "slider.json")

La macro Q_PLUGIN_METADATA exporta el plugin de la clase SliderPlugin a la librería acc_sliderplugin. El primer argumento es el IID del plugin y el segundo es un archivo json opcional que contiene información de metadatos para el plugin. Para más información sobre plugins, puedes consultar el documento de descripción general de plugins.

No importa si necesitas que el plugin esté enlazado estática o dinámicamente con la aplicación.

Implementación de fábricas de interfaces

Si no quieres proporcionar plugins para tus interfaces de accesibilidad, puedes utilizar una fábrica de interfaces (QAccessible::InterfaceFactory), que es la forma recomendada de proporcionar interfaces accesibles en una aplicación enlazada estáticamente.

Una fábrica es un puntero de función para una función que toma los mismos parámetros que QAccessiblePlugin's create() - un QString y un QObject. También funciona de la misma manera. La fábrica se instala con la función installFactory(). Damos un ejemplo de cómo crear una fábrica para la interfaz 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);
    ...
}

Accessible

Habilita la accesibilidad de los elementos QML

QAccessible

Enums y funciones estáticas relacionadas con la accesibilidad

QAccessibleActionInterface

Implementa soporte para acciones invocables en la interfaz

QAccessibleAnnouncementEvent

Se utiliza para solicitar el anuncio de un mensaje determinado por parte de las tecnologías de asistencia

QAccessibleAttributesInterface

Implementa el soporte para informar de los atributos de un objeto accesible

QAccessibleEditableTextInterface

Implementa soporte para objetos con texto editable

QAccessibleEvent

La clase base para las notificaciones de accesibilidad

QAccessibleInterface

Define una interfaz que expone información sobre objetos accesibles

QAccessibleObject

Implementa partes de QAccessibleInterface para QObjects

QAccessiblePlugin

Clase base abstracta para plugins que proporcionan información sobre la accesibilidad de los elementos de la interfaz de usuario

QAccessibleSelectionInterface

Implementa soporte para el manejo de la selección

QAccessibleStateChangeEvent

Notifica al marco de accesibilidad que el estado de un objeto ha cambiado.

QAccessibleTableCellInterface

Implementa la compatibilidad con la interfaz IAccessibleTable2 Cell

QAccessibleTableInterface

Implementa la compatibilidad con la interfaz IAccessibleTable2.

QAccessibleTableModelChangeEvent

Indica un cambio en una tabla, lista o árbol en el que se han añadido o eliminado celdas. Si el cambio afecta a un número de filas, firstColumn y lastColumn devolverán -1. En el caso de las columnas, las funciones de fila pueden devolver -1.

QAccessibleTextCursorEvent

Notifica los movimientos del cursor

QAccessibleTextInsertEvent

Notifica la inserción de texto

QAccessibleTextInterface

Implementa el manejo de texto

QAccessibleTextRemoveEvent

Notifica la eliminación de texto

QAccessibleTextSelectionEvent

Señala un cambio en la selección de texto de un objeto

QAccessibleTextUpdateEvent

Notifica los cambios de texto. Esto es para accesibles que soportan texto editable como ediciones de línea. Este evento se produce, por ejemplo, cuando una parte del texto seleccionado se sustituye al pegar un nuevo texto o en el modo de anulación de los editores

QAccessibleValueChangeEvent

Describe un cambio de valor de un objeto accesible

QAccessibleValueInterface

Implementa soporte para objetos que manipulan un valor

QAccessibleWidget

Implementa la interfaz QAccessibleInterface para 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.