Share via


Asegurarse de que el nombre de los elementos de la interfaz de usuario es correcto

En este tema se describe la manera correcta de especificar los nombres de los elementos de la interfaz de usuario en las aplicaciones de Microsoft Win32 para que Microsoft Active Accessibility pueda exponer con precisión los nombres a las aplicaciones cliente mediante la propiedad IAccessibleName.

La información de esta sección solo se aplica a Microsoft Active Accessibility. No incluye a las aplicaciones que usan Automatización de la interfaz de usuario de Microsoft ni a las basadas en lenguajes de marcado, como HTML, HTML dinámico (DHTML) o XML.

Información general

En Microsoft Active Accessibility, cada elemento de la interfaz de usuario de una aplicación se representa mediante un objeto que expone la interfaz IAccessible.. Las aplicaciones cliente usan las propiedades y los métodos de la interfaz IAccessible para interactuar con el elemento de la interfaz de usuario y para recuperar información sobre él. Una de las propiedades más importantes expuestas por la interfaz IAccessible es la propiedad Name. Las aplicaciones cliente dependen de la propiedad Name para encontrar, identificar o anunciar un elemento de la interfaz de usuario al usuario. Si Microsoft Active Accessibility no puede exponer correctamente la propiedad Name de un elemento de la interfaz de usuario determinado, las aplicaciones cliente no podrán presentar ese elemento de la interfaz de usuario al usuario y el elemento de la interfaz de usuario será inaccesible para los usuarios con discapacidades.

Cómo la nomenclatura incorrecta provoca problemas

Para ilustrar los problemas causados por una nomenclatura incorrecta de los elementos de la interfaz de usuario, considere el formulario de entrada de nombre que se muestra en la ilustración siguiente.

illustration of a simple form for entering first and last name

Aunque los elementos de la interfaz de usuario del formulario parecen estar bien, la implementación mediante programación es incorrecta. Para un cliente de Microsoft Active Accessibility, como un lector de pantalla, la propiedad Name del control de edición superior es "Apellidos:" y la propiedad Name del control de edición inferior es una cadena vacía (""). El lector de pantalla leerá el control de edición superior como "Apellidos", aunque se espera que el usuario escriba el nombre. El lector de pantalla leerá el segundo control de edición como "sin nombre", por lo que el usuario no tendrá ni idea de lo que escribir en el segundo control de edición. El lector de pantalla no puede ayudar al usuario a escribir datos en este sencillo formulario.

Otro problema con el formulario es que ninguna tecla de método abreviado está asignada a ninguno de los controles de edición. El usuario se ve obligado a desplazarse hasta los controles mediante la tecla de tabulación o a usar el mouse.

En las secciones siguientes se explica el origen de estos problemas y se proporcionan instrucciones para corregirlos.

Cómo obtiene MSAA la propiedad Name

Microsoft Active Accessibility obtiene la cadena de propiedad Name de diferentes ubicaciones en función del tipo del elemento de la interfaz de usuario. Con la mayoría de los elementos de la interfaz de usuario que tienen texto de ventana asociado, Microsoft Active Accessibility usa el texto de ventana como cadena de propiedad Name. Algunos ejemplos de este tipo de elemento de la interfaz de usuario incluyen controles como botones, elementos de menú e información sobre herramientas.

Con los controles siguientes, Microsoft Active Accessibility omite el texto de ventana y, en su lugar, busca una etiqueta de texto estático (o etiqueta de cuadro de grupo) inmediatamente anterior al control en el orden de tabulación.

  • Cuadros combinados
  • Selectores de fecha y hora
  • Controles de edición y edición enriquecida
  • Controles de dirección IP
  • Cuadros de lista
  • Vistas de lista
  • Barras de progreso
  • Barras de desplazamiento
  • Controles estáticos que tienen el estilo de SS_ICON o SS_BITMAP
  • Barras de seguimiento
  • Vistas de árbol

Si los controles anteriores no van acompañados de etiquetas de texto estático o si las etiquetas no se implementan correctamente, Microsoft Active Accessibility no puede proporcionar la propiedad Name correcta a las aplicaciones cliente.

La mayoría de los controles anteriores tienen realmente un texto de ventana asociado. El editor de recursos genera automáticamente el texto de ventana, que consta de una cadena genérica, como "edit1" o "listbox3". Aunque los desarrolladores pueden reemplazar el texto de ventana generado por texto más significativo, la mayoría nunca lo hace. Dado que el texto de ventana generado no tiene ningún significado para el usuario, Microsoft Active Accessibility lo omite y usa en su lugar la etiqueta de texto estático.

Cómo encontrar y corregir problemas de nomenclatura

En el formulario de entrada de nombre que se muestra en "Cómo la nomenclatura incorrecta provoca problemas", la causa de los problemas es que el orden de tabulación de los controles es incorrecto. Al examinar la interfaz de usuario con una herramienta de prueba, como Inspect, se revelarían los problemas con la jerarquía de objetos. En la captura de pantalla siguiente se muestra la jerarquía de objetos interrumpidos del formulario de entrada de nombre tal y como aparece en Inspect.

screen shot of the inspect tool showing an incorrect object hierarchy of the name entry form

En la captura de pantalla anterior, observe que la jerarquía de objetos no coincide con la estructura de los controles que aparecen en la interfaz de usuario del formulario de entrada de nombre. Observe también que Inspect ha asignado un nombre incorrecto al penúltimo elemento (es el control de edición para escribir el nombre y se le debe llamar "Nombre:"). Por último, observe que Inspect no pudo encontrar un nombre para el último elemento (es el control de edición para escribir el apellido y debe tener el nombre "Apellidos:").

En el ejemplo siguiente se muestra el contenido del archivo de recursos para el formulario de entrada de nombre. Observe que el orden de tabulación no es coherente con la estructura lógica de los controles que aparecen en la interfaz de usuario. Observe también que no se especifican teclas de método abreviado para los dos controles de edición.

IDD_INPUTNAME DIALOGEX 22, 17, 312, 118
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Enter your name"
FONT 8, "System", 0, 0, 0x0
BEGIN
    DEFPUSHBUTTON   "OK",IDOK,179,35,30,11,WS_GROUP
    LTEXT           "First Name:",IDC_STATIC,8,16,43,8
    LTEXT           "Last Name:",IDC_STATIC,8,33,43,8
    EDITTEXT        IDC_EDIT1,53,15,120,12,ES_AUTOHSCROLL
    EDITTEXT        IDC_EDIT2,53,34,120,12,ES_AUTOHSCROLL
END

Para corregir los problemas con el formulario de entrada de nombre, el archivo de recursos (.rc) debe editarse para especificar métodos abreviados de teclado y los controles deben colocarse en el orden siguiente:

  1. La etiqueta de texto estático "&Nombre:".
  2. Control de edición para escribir el nombre (IDC_EDIT1).
  3. La etiqueta de texto estático "&Apellidos:".
  4. Control de edición para escribir el apellido (IDC_EDIT2).
  5. Botón de comando predeterminado "Aceptar".

En el ejemplo siguiente se muestra el archivo de recursos corregido para el formulario de entrada de nombre:

IDD_INPUTNAME DIALOGEX 22, 17, 312, 118
STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Enter your name"
FONT 8, "System", 0, 0, 0x0
BEGIN
    LTEXT           "&First Name:",IDC_STATIC,8,16,43,8
    EDITTEXT        IDC_EDIT1,53,15,120,12,ES_AUTOHSCROLL
    LTEXT           "&Last Name:",IDC_STATIC,8,33,43,8
    EDITTEXT        IDC_EDIT2,53,34,120,12,ES_AUTOHSCROLL
    DEFPUSHBUTTON   "OK",IDOK,179,35,30,11,WS_GROUP
END

Para realizar correcciones en un archivo de recursos, puede editar el archivo directamente o puede usar la herramienta de orden de tabulación de Microsoft Visual Studio. Puede acceder a la herramienta de orden de tabulación en Visual Studio presionando CTRL+D o seleccionando Orden de tabulación en el menú Formato.

Después de corregir y volver a compilar la aplicación, la interfaz de usuario del formulario de entrada de nombre tendrá el mismo aspecto que antes. Sin embargo, Microsoft Active Accessibility ahora proporcionará las propiedades Name correctas a las aplicaciones cliente, y establecerá el foco correctamente cuando el usuario presione los métodos abreviados de teclado ALT+F o ALT+L. Además, Inspect mostrará la jerarquía de objetos correcta, como se ilustra en la captura de pantalla siguiente.

screen shot of the accessible explorer tool showing a correct object hierarchy of the name entry form

Cómo asignar un nombre correctamente a una barra de seguimiento

Al definir una barra de seguimiento (o control deslizante), asegúrese de que la etiqueta de texto estático principal de dicha barra aparezca antes que ella y que las etiquetas de texto estático de los intervalos mínimo y máximo aparezcan después. Recuerde que Microsoft Active Accessibility usa la etiqueta de texto estático que precede inmediatamente a un control como propiedad Name del control. Al colocar la etiqueta de texto estático principal inmediatamente antes que la barra de seguimiento y las demás etiquetas después de ella, se garantiza que Microsoft Active Accessibility proporciona la propiedad Name correcta a un cliente.

En la ilustración siguiente se muestra una barra de seguimiento típica con una etiqueta de texto estático principal llamada "Velocidad" y etiquetas de texto estático para los intervalos mínimo ("min") y máximo ("max").

illustration of a trackbar control that has a main label and labels for the minimum and maximum ranges

En el ejemplo siguiente se muestra la manera correcta de definir una barra de seguimiento y sus etiquetas de texto estático en el archivo de recursos:

BEGIN
    ...

    LTEXT           "&Speed",IDC_STATIC,47,20,43,8
    CONTROL         "",IDC_SLIDER1,"msctls_trackbar32",
                    TBS_AUTOTICKS | TBS_BOTH | WS_TABSTOP,
                    32,32,62,23
    LTEXT           "min",IDC_STATIC,16,37,15,8
    LTEXT           "max",IDC_STATIC,94,38,43,8

    ...
END

Cómo usar etiquetas invisibles para asignar nombres a controles

No siempre es posible o deseable tener una etiqueta visible para cada control. Por ejemplo, a veces agregar etiquetas puede provocar cambios no deseados en la apariencia de la interfaz de usuario. En este caso, puede usar etiquetas invisibles. Microsoft Active Accessibility seguirá recogiendo el texto asociado a una etiqueta invisible, pero la etiqueta no aparecerá en la interfaz de usuario visual ni interferirá con ella.

Al igual que con las etiquetas visibles, una etiqueta invisible debe preceder inmediatamente al control en el orden de tabulación. Para que una etiqueta sea invisible en un archivo de recursos (.rc), agregue NOT WS_VISIBLE o |~WS_VISIBLE a la parte de estilo del control de texto estático. Si usa el Editor de recursos en Visual Studio, puede establecer la propiedad Visible en False.

Cómo usar la anotación directa para especificar la propiedad Name

Los servidores proxy predeterminados incluidos en el componente del entorno de ejecución de Microsoft Active Accessibility, Oleacc.dll, proporcionan automáticamente un objeto IAccessible para todos los controles estándar de Windows. Si personaliza un control estándar de Windows, los servidores proxy predeterminados harán todo lo posible para proporcionar con precisión todas las propiedades IAccessible para el control personalizado. Debe probar exhaustivamente un control personalizado para asegurarse de que los servidores proxy predeterminados proporcionan valores de propiedad precisos y completos. Si las pruebas revelan valores de propiedad inexactos o incompletos, es posible que pueda usar la técnica de anotación dinámica denominada anotación directa para proporcionar valores de propiedad correctos y agregar los que faltan.

Tenga en cuenta que la anotación dinámica no es solo para los controles compatibles con los servidores proxy de Microsoft Active Accessibility. También puede usarla para modificar o proporcionar propiedades para cualquier control que proporcione su propia implementación de IAccessible.

Esta sección se centra en el uso de anotaciones directas para proporcionar un valor correcto para la propiedad Name del objeto IAccessible para un control. También puede usar anotaciones directas para proporcionar otros valores de propiedades. Además, existen otras técnicas de anotación dinámica además de la anotación directa, y las características y funcionalidades de Dynamic Annotation API se extienden mucho más allá de lo que se describe en esta sección. Para más información sobre la anotación dinámica, consulte Dynamic Annotation API.

Pasos para anotar la propiedad Name

El uso de la anotación directa para cambiar la propiedad Name de un control implica los pasos siguientes.

  1. Incluya los siguientes archivos de encabezado:

    • Initguid.h
    • Oleacc.h

    Nota:

    Para definir GUID, debe incluir Initguid.h delante de Oleacc.h en el mismo archivo.

     

  2. Inicialice la biblioteca de Modelo de objetos componentes (COM) llamando a la función CoInitializeEx, normalmente durante el proceso de inicialización de la aplicación.

  3. Poco después de crear el control de destino (normalmente durante el mensaje WM_INITDIALOG), cree una instancia del administrador de anotaciones y obtenga un puntero a su puntero IAccPropServices.

  4. Anote la propiedad Name del control de destino mediante el método IAccPropServices::SetHwndPropStr.

  5. Libere el puntero IAccPropServices.

  6. Antes de que se destruya el control de destino (normalmente al controlar el mensajeWM_DESTROY), cree una instancia del administrador de anotaciones y obtenga un puntero a su puntero interfaz IAccPropServices.

  7. Use el método IAccPropServices::ClearHwndProps para borrar las anotaciones de la propiedad Name del control de destino.

  8. Libere el puntero IAccPropServices.

  9. Antes de que la aplicación salga (normalmente al procesar el mensaje WM_DESTROY), libere la biblioteca COM llamando a la función CoUninitialize.

La función IAccPropServices::SetHwndPropStr toma cinco parámetros. Los tres primeros ( hwnd, idObject e idChild) se combinan para identificar el control. El cuarto parámetro, idProp, especifica el identificador de la propiedad que se va a cambiar. Para cambiar la propiedad Name, establezca idProp en PROPID_ACC_NAME. (Para obtener una lista de otras propiedades que puede establecer mediante anotaciones directas, consulte Uso de anotaciones directas). El último parámetro de SetHwndPropStr, str, es la nueva cadena que se usará como propiedad Name.

Ejemplo de anotación de la propiedad Name

En el código de ejemplo siguiente se muestra cómo usar la anotación directa para cambiar la propiedad Name del objeto IAccessible para un control. Para simplificar las cosas, en el ejemplo se usa una cadena codificada de forma rígida ("Nuevo nombre de control") para establecer la propiedad Name. Las cadenas codificadas de forma rígida no deben usarse en la versión final de la aplicación porque no se pueden localizar. En su lugar, cargue siempre cadenas del archivo de recursos. Además, el ejemplo no muestra las llamadas a las funciones CoInitializeEx y CoUninitialize.

#include <initguid.h>
#include <oleacc.h>

// AnnotateControlName - Uses direct annotation to change the Name property 
// of the IAccessible object for a control.
//
// hDlg - Handle of the dialog box that contains the control.
// hwndCtl - Handle of the control whose Name property is to be changed.
HRESULT AnnotateControlName(HWND hDlg, HWND hwndCtl)
{
    HRESULT hr;        

    IAccPropServices *pAccPropSvc = NULL;  

    // Create an instance of the annotation manager and retrieve the 
    // IAccPropServices pointer.
    hr = CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER, 
        IID_IAccPropServices, (void **) &pAccPropSvc);

    if (hr != S_OK || pAccPropSvc == NULL)
        return hr;

    // Set the Name property for the control.
    // Note: A hard-coded string is used here to keep the example simple.
    // Always use localizable string resources in your applications. 
    hr = pAccPropSvc->SetHwndPropStr(hwndCtl, OBJID_CLIENT, CHILDID_SELF, 
        PROPID_ACC_NAME, L"New Control Name");

    pAccPropSvc->Release();
    
    return hr;
}

// RemoveAnnotatedNameFromControl - Removes the annotated name from the 
// Name property of the IAccessible object for a control.
//
// hDlg - Handle of the dialog box that contains the control.
// hwndCtl - Handle of the control whose annotated name is to be removed.
HRESULT RemoveAnnotatedNameFromControl(HWND hDlg, HWND hwndCtl)
{
    HRESULT hr;

    IAccPropServices *pAccPropSvc = NULL;

    // Create an instance of the annotation manager and retrieve the 
    // IAccPropServices pointer.
    hr = CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER, 
        IID_IAccPropServices, (void **) &pAccPropSvc);

    if (hr != S_OK || pAccPropSvc == NULL)
        return hr;

    // Remove the annotated name from the Name property for the control.
    MSAAPROPID propid = PROPID_ACC_NAME;
    hr = pAccPropSvc->ClearHwndProps(hwndCtl, OBJID_CLIENT, CHILDID_SELF, 
        &propid, 1);

    // Release the annotation manager.
    pAccPropSvc->Release();

    return hr;
}