Поделиться через


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

В этом разделе описывается правильный способ указать имена элементов пользовательского интерфейса в приложениях 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 определенного элемента пользовательского интерфейса, клиентские приложения не смогут представить этот элемент пользовательского интерфейса пользователю, а элемент пользовательского интерфейса будет недоступным для пользователей с ограниченными возможностями.

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

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

иллюстрация простой формы для ввода имени и фамилии

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

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

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

Как MSAA получает свойство имени

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

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

  • Комбинированные списки
  • Средства выбора даты и времени
  • Элементы управления редактированием и расширенного редактирования текста
  • Управление IP-адресами
  • Списки
  • Представления списка
  • Индикаторы выполнения
  • Полосы прокрутки
  • Статические элементы управления с стилем SS_ICON или SS_BITMAP
  • Панели отслеживания
  • Древовидное представление

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

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

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

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

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

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

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

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. Кнопка "OK" по умолчанию.

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

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. Кроме того, проверка отобразит правильную иерархию объектов, как показано на следующем снимке экрана.

Снимок экрана средства обозревателя со специальными возможностями, показывающий правильную иерархию объектов формы записи имени

Как правильно назвать ползунок

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

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

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

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

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.

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

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

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

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

Шаги по аннотации свойства имени

Использование прямой аннотации для изменения свойства 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 объекта 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;
}