Обеспечение правильности именованных элементов пользовательского интерфейса

В этом разделе описывается правильный способ указать имена элементов пользовательского интерфейса в приложениях Microsoft Win32, чтобы microsoft Active Accessibility точно предоставлял имена клиентским приложениям через свойство IAccessibleName.

Сведения в этом разделе относятся только к microsoft Active Accessibility. Он не применяется к приложениям, используюющим Microsoft модель автоматизации пользовательского интерфейса или на основе языков разметки, таких как HTML, Динамический HTML (DHTML) или XML.

Обзор

В Microsoft Active Accessibility каждый элемент пользовательского интерфейса в приложении представлен объектом, предоставляющим интерфейс IAccessible . Клиентские приложения используют свойства и методы интерфейса IAccessible для взаимодействия с элементом пользовательского интерфейса и получения сведений об этом. Одним из наиболее важных свойств, предоставляемых интерфейсом IAccessible , является свойство Name. Клиентские приложения используют свойство Name для поиска, идентификации или объявления элемента пользовательского интерфейса пользователю. Если microsoft Active Accessibility не может правильно предоставить свойство Name определенного элемента пользовательского интерфейса, клиентские приложения не смогут представить этот элемент пользовательского интерфейса пользователю, а элемент пользовательского интерфейса будет недоступным для пользователей с ограниченными возможностями.

Как неправильное именование вызывает проблемы

Чтобы иллюстрировать проблемы, вызванные неправильным именованием элементов пользовательского интерфейса, рассмотрим форму записи имен, показанную на следующем рисунке.

illustration of a simple form for entering first and last name

Хотя элементы пользовательского интерфейса в форме выглядят нормально, программная реализация некорректна. Для клиента Microsoft Active Accessibility, например средства чтения с экрана, свойство Name верхнего элемента управления редактирования — "Фамилия:", а свойство Name нижнего элемента управления редактирования — пустая строка (""). Средство чтения с экрана считывает верхний элемент управления редактирования как "Фамилия", хотя пользователь, как ожидается, ввести имя. Средство чтения с экрана считывает второй элемент управления редактирования как "нет имени", поэтому пользователь не будет иметь представления о том, что нужно ввести во второй элемент управления редактирования. Средство чтения с экрана не может помочь пользователю вводить данные в эту простую форму.

Другая проблема с формой заключается в том, что сочетания клавиш не назначаются ни одному из элементов управления редактирования. Пользователь вынужден переходить на вкладку элементов управления или использовать мышь.

В следующих разделах объясняется источник этих проблем и приведены рекомендации по их исправлению.

Как MSAA получает свойство name

Microsoft Active Accessibility получает строку свойства Name из разных расположений в зависимости от типа элемента пользовательского интерфейса. Для большинства элементов пользовательского интерфейса, имеющих связанный текст окна, Microsoft Active Accessibility использует текст окна в качестве строки свойства Name. Примеры этого типа элемента пользовательского интерфейса включают такие элементы управления, как кнопки, элементы меню и подсказки.

Для следующих элементов управления Microsoft Active Accessibility игнорирует текст окна и вместо этого ищет статическую текстовую метку (или метку поля группы) непосредственно перед элементом управления в порядке табуляции.

  • Поля со списком
  • Средства выбора даты и времени
  • Редактирование и элементы управления "Расширенные изменения"
  • Элементы управления IP-адресами
  • Списки
  • Представления списка
  • Индикаторы выполнения
  • Scrollbars
  • Статические элементы управления с стилем SS_ICON или SS_BITMAP
  • Панели отслеживания
  • Представления дерева

Если предыдущие элементы управления не сопровождаются статическими текстовыми метками или если метки не реализованы правильно, microsoft Active Accessibility не может предоставить правильное свойство Name клиентским приложениям.

Большинство предыдущих элементов управления фактически имеют связанный текст окна. Редактор ресурсов автоматически создает текст окна, состоящий из универсальной строки, например edit1 или listbox3. Хотя разработчики могут заменить созданный текст окна более значимым текстом, большинство из них никогда не делают. Так как созданный текст окна не имеет значения для пользователя, Microsoft Active Accessibility игнорирует его и использует сопровождающую статическую текстовую метку.

Поиск и исправление проблем именования

В форме записи имени, показанной в разделе "Как неправильное именование вызывает проблемы", причина проблем заключается в том, что порядок вкладок элементов управления неверный. Изучение пользовательского интерфейса с помощью средства тестирования, такого как Проверка , покажет проблемы с иерархией объектов. На следующем снимке экрана показана сломанная иерархия объектов формы записи имени, как показано в разделе "Проверка".

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

На предыдущем снимке экрана обратите внимание, что иерархия объектов не соответствует структуре элементов управления, так как они отображаются в пользовательском интерфейсе формы записи имени. Кроме того, обратите внимание, что Проверка назначила неверное имя следующему элементу (это элемент управления редактирования для ввода первого имени и должен иметь имя "Имя:". Наконец, обратите внимание, что проверка не удалось найти имя последнего элемента (это элемент управления редактирования для ввода фамилии и должен иметь имя "Фамилия:".

В следующем примере показано содержимое файла ресурса для формы записи имени. Обратите внимание, что порядок вкладок не соответствует логической структуре элементов управления, так как они отображаются в пользовательском интерфейсе. Кроме того, обратите внимание, что для двух элементов управления правки не указаны сочетания клавиш.

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

Чтобы исправить проблемы с формой записи имени, файл ресурса (RC) должен быть изменен, чтобы указать сочетания клавиш, и элементы управления должны размещаться в следующем порядке:

  1. Статическое текстовое метка "&First Name:".
  2. Элемент управления редактирования для ввода первого имени (IDC_EDIT1).
  3. Статическое текстовое метка "&Фамилия:".
  4. Элемент управления редактирования для ввода фамилии (IDC_EDIT2).
  5. Кнопка нажатия кнопки "ОК" по умолчанию.

В следующем примере показан исправленный файл ресурса для формы записи имени:

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

Чтобы внести исправления в файл ресурсов, можно изменить файл напрямую или использовать средство "Порядок вкладок" в Microsoft Visual Studio. Вы можете получить доступ к средству "Порядок вкладок" в Visual Studio, нажав клавиши CTRL+D или выбрав пункт "Порядок вкладок" в меню "Формат ".

После исправления и перестроения приложения пользовательский интерфейс формы записи имен будет выглядеть так же, как и раньше. Однако microsoft Active Accessibility теперь предоставляет правильные свойства имени клиентским приложениям и правильно задает фокус, когда пользователь нажимает сочетания клавиш ALT+F или ALT+L. Кроме того, проверка отобразит правильную иерархию объектов, как показано на следующем снимке экрана.

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

Правильное имя панели отслеживания

При определении панели отслеживания (или ползунка) убедитесь, что основная статическое текстовое метка для панели отслеживания отображается перед панелью отслеживания и что статические текстовые метки для минимального и максимального диапазона отображаются после панели отслеживания. Помните, что Microsoft Active Accessibility использует статическую текстовую метку, которая сразу же предшествует элементу управления в качестве свойства Name для элемента управления. Размещение основной статической текстовой метки непосредственно перед панелью отслеживания и другими метками после нее гарантирует, что Microsoft Active Accessibility предоставляет правильное свойство Name клиенту.

На следующем рисунке показана типичная панель отслеживания с основной статической текстовой меткой "Скорость", а статические текстовые метки для минимальных ("min") и максимальных ("max") диапазонов.

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

В следующем примере показан правильный способ определения панели отслеживания и его статических текстовых меток в файле ресурса:

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

Использование невидимых меток для элементов управления именами

Не всегда возможно или желательно иметь видимую метку для каждого элемента управления. Например, иногда добавление меток может привести к нежелательным изменениям в внешнем виде пользовательского интерфейса. В этом случае можно использовать невидимые метки. Microsoft Active Accessibility по-прежнему будет собирать текст, связанный с невидимой меткой, но метка не будет отображаться или не вмешиваться в визуальный интерфейс.

Как и в случае с видимыми метками, невидимая метка должна немедленно предшествовать элементу управления в порядке табуляции. Чтобы сделать метку невидимой в файле ресурсов (RC), добавьте NOT WS_VISIBLE или |~WS_VISIBLE в часть стиля статического элемента управления текстом. Если вы используете редактор ресурсов в Visual Studio, можно задать для свойства Visible значение False.

Как использовать прямую заметку для указания свойства name

Прокси-серверы по умолчанию, включенные в компонент среды выполнения Microsoft Active Accessibility, Oleacc.dll, автоматически предоставляют объект I Access для всех стандартных элементов управления Windows. Если вы настраиваете стандартный элемент управления Windows, прокси-серверы по умолчанию позволяют точно предоставить все свойства IAccessible для настраиваемого элемента управления. Необходимо тщательно проверить настраиваемый элемент управления, чтобы убедиться, что прокси-серверы по умолчанию предоставляют точные и полные значения свойств. Если тестирование показывает неточные или неполные значения свойств, вы можете использовать метод динамической заметки, называемый прямой заметкой для предоставления правильных значений свойств и добавления отсутствующих значений свойств.

Обратите внимание, что динамическая заметка не только для элементов управления, поддерживаемых прокси-серверами Microsoft Active Accessibility. Его также можно использовать для изменения или предоставления свойств для любого элемента управления, предоставляющего собственную реализацию IAccessible .

В этом разделе основное внимание уделяется использованию прямой заметки для указания правильного значения свойства Name объекта IAccessible для элемента управления. Вы также можете использовать прямую заметку для предоставления других значений свойств. Кроме того, доступны другие методы динамической заметки рядом с прямой заметкой, а функции и возможности API динамических заметок расширяются далеко за рамки описанного в этом разделе. Дополнительные сведения о динамической заметке см. в разделе API динамических заметок.

Действия по аннотации свойства name

Использование прямой заметки для изменения свойства name элемента управления включает в себя следующие действия.

  1. Включите следующие файлы заголовков:

    • Initguid.h
    • Oleacc.h

    Примечание.

    Чтобы определить идентификаторы GUID, необходимо включить Initguid.h перед Oleacc.h в том же файле.

     

  2. Инициализировать библиотеку объектной модели компонента (COM), вызвав функцию CoInitializeEx , обычно во время процесса инициализации приложения.

  3. Вскоре после создания целевого элемента управления (обычно во время WM_INITDIALOG сообщения) создайте экземпляр диспетчера заметок и получите указатель на указатель IAccPropServices.

  4. Заметите свойство Name целевого элемента управления с помощью метода IAccPropServices::SetHwndPropStr.

  5. Отпустите указатель IAccPropServices .

  6. Перед уничтожением целевого элемента управления (обычно при обработке сообщения WM_DESTROY), создайте экземпляр диспетчера заметок и получите указатель на его интерфейс IAccPropServices.

  7. Используйте метод IAccPropServices::ClearHwndProps, чтобы очистить заметки свойств Name из целевого элемента управления.

  8. Отпустите указатель IAccPropServices .

  9. Перед выходом приложения (обычно при обработке сообщения WM_DESTROY ) выпустите библиотеку COM, вызвав функцию CoUninitialize .

Функция IAccPropServices::SetHwndPropStr принимает пять параметров. Первые три — hwnd, idObject и idChild — объединяются для идентификации элемента управления. Четвертый параметр, idProp, указывает идентификатор свойства, который необходимо изменить. Чтобы изменить свойство Name, задайте для idProp значение PROPID_ACC_NAME. (Список других свойств, которые можно задать с помощью прямой заметки, см. в разделе Использование прямой заметки.) Последний параметр SetHwndPropStr, str, является новой строкой, используемой в качестве свойства Name.

Пример аннотирования свойства Name

В следующем примере кода показано, как использовать прямую заметку для изменения свойства Name объекта IAccessible для элемента управления. Для простоты в примере используется жестко закодированная строка ("Новое имя элемента управления") для задания свойства Name. Жестко закодированные строки не следует использовать в окончательной версии приложения, так как они не могут быть локализованы. Вместо этого всегда загружайте строки из файла ресурсов. Кроме того, в примере не отображаются вызовы функций CoInitializeEx и 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;
}