Специальные возможности
|
Объект-источник | Целевой объект | Отношение |
---|---|---|
Slider | Indicator | Управляющий объект |
Indicator | Slider | Управляемый объект |
Slider | Application | Предок |
Application | Slider | Потомок |
PushButton | Indicator | Сосед |
Специальными возможностями управляют статические функции QAccessible, которые мы коротко рассмотрим. Они производят интерфейсы QAccessible, создают дерево объектов и инициируют соединение с MSAA или другой платформой технологий. Если вы заинтересованы только в том, чтобы создать ваше приложение специальных возможностей, вы можете спокойно пропустить эту часть до раздела Реализация специальных возможностей.
Связь между клиентом и сервером устанавливается, когда вызывается setRootObject(). Это происходит при создании экземпляра класса QApplication, так что вы не должны делать это самостоятельно.
Когда QObject вызывает updateAccessibility(), клиенты, которые слушают события, уведомляются об изменениях. Эта функция используется для отправки событий вспомогательной технологии, и события специальных возможностей отправляются по updateAccessibility().
queryAccessibleInterface() возвращает интерфейсы специальных возможностей для QObject. Все виджеты в Qt предоставляют интерфейсы; если же вам необходимы интерфейсы для управления поведением других подклассов QObject, вы должны реализовать интерфейсы самостоятельно, хотя класс QAccessibleObject реализует для вас часть функциональности.
The factory that produces accessibility interfaces for QObjects is a function of type QAccessible::InterfaceFactory. Можно иметь несколько установленных фабрик. Последняя установленная фабрика будет первой, у которой будут запрошены интерфейсы. queryAccessibleInterface() uses the factories to create interfaces for QObjects. Как правило, вы не должны беспокоиться о фабриках, поскольку вы можете реализовать подключаемые модули, которые производят интерфейсы. Мы дадим примеры обоих подходов позже.
Для обеспечения поддержки специальных возможностей в виджетах и других элементах интерфейса пользователя, вам необходимо реализовать интерфейс QAccessibleInterface и разместить его в QAccessiblePlugin. Также можно скомпилировать интерфейс в приложении и обеспечить для него QAccessible::InterfaceFactory. Фабрика может быть использована, если вы используете статическую линковку и не хотите дополнительно усложнять подключаемый модуль. Это может быть преимуществом, если вы, например, поставляете стороннюю библиотеку.
Все виджеты и другие элементы интерфейса пользователя должны иметь интерфейсы и подключаемые модули. Если вы хотите, чтобы ваше приложение поддерживало специальные возможности, вам необходимо учитывать следующее:
In general, it is recommended that you are somewhat familiar with MSAA, which Qt originally was built for. Вам необходимо также изучить значения перечислений QAccessible, описывающих роли, действия, отношения и события, которые вам нужно принимать во внимание.
Обратите внимание на то, что вы можете исследовать, как виджеты Qt реализуют свои специальные возможности. Одной из основных проблем со стандартом MSAA является то, что интерфейсы часто реализуются противоречивыми способами. Это осложняет жизнь клиентам и часто заставляет строить предположения о функциональности объектов.
Можно создать интерфейсы, унаследовав QAccessibleInterface и реализовав его чисто виртуальные функции. На практике, однако, предпочтительнее наследовать от QAccessibleObject или QAccessibleWidget, которые уже реализуют часть функциональности для вас. В следующем разделе мы увидим пример реализации специальных возможностей для виджета путем наследования класса QAccessibleWidget.
При реализации специальных возможностей для виджетов, как правило, наследуют QAccessibleWidget, который является вспомогательным классом для виджетов. Another available convenience class, which is inherited by QAccessibleWidget, is the QAccessibleObject, which implements part of the interface for QObjects.
QAccessibleWidget предоставляет следующую функциональность:
Вместо того чтобы создавать пользовательский виджет и реализовывать интерфейс для него, мы покажем, как специальные возможности могут быть реализованы в одном из стандартных виджетов Qt: QSlider. Создание специальных возможностей для этого виджета демонстрирует многие проблемы, с которыми необходимо столкнуться при создании специальных возможностей у пользовательского виджета.
Ползунок - сложный элемент управления, который функционирует как контроллер для дочерних элементов специальных возможностей. Эти отношения должны быть известны через интерфейс (relationTo() и navigate()). Это можно сделать с помощью управляющего сигнала, который является механизмом, предоставляемым QAccessibleWidget. Делаем это в конструкторе:
QAccessibleSlider::QAccessibleSlider(QWidget *w) : QAccessibleAbstractSlider(w) { Q_ASSERT(slider()); addControllingSignal(QLatin1String("valueChanged(int)")); }
Выбор показанного сигнала не важен, те же принципы применяются ко всем сигналам, объявленным таким же образом. Обратите внимание на то, что мы используем QLatin1String, чтобы гарантировать, что имя сигнала указано корректно.
Когда объект специальных возможностей изменяется таким образом, что пользователи должны об этом узнать, он уведомляет клиентов об изменении, отправляя им событие через интерфейс специальных возможностей. Так же как QSlider вызвал updateAccessibility(), чтобы показать, что его значение изменилось:
void QAbstractSlider::setValue(int value) ... QAccessible::updateAccessibility(this, 0, QAccessible::ValueChanged); ... }
Обратите внимание на то, что вызов осуществляется после изменения значения ползунка, поскольку клиенты могут запросить новое значение сразу же после получения события.
Интерфейс должен быть в состоянии вычислить ограничительные прямоугольники себя и любых дочерних элементов, которые не предоставляют собственный интерфейс. QAccessibleSlider имеет три таких дочерних элемента, определенных в закрытом перечислении SliderElements, у которого есть следующие значения: PageLeft (прямоугольник с левой стороны от ручки ползунка), PageRight (прямоугольник с правой стороны от ручки ползунка) и Position (ручка ползунка). Вот реализация функции 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); } ...
Первая часть функции, которую мы опустили, использует текущий стиль для подсчета ограничительного прямоугольника ручки ползунка; он сохраняется в srect. Обратите внимание, что дочерний элемент child со значением 0, обрабатываемый меткой default в коде выше, это сам ползунок, так что мы можем просто вернуть ограничивающий прямоугольник QSlider, полученный из родительского класса, который фактически получает значение из QAccessibleWidget::rect().
QPoint tp = slider()->mapToGlobal(QPoint(0,0)); return QRect(tp.x() + rect.x(), tp.y() + rect.y(), rect.width(), rect.height()); }
Перед тем, как прямоугольник будет возвращен, он должен быть отображен на экранные координаты.
QAccessibleSlider должен переопределить QAccessibleInterface::childCount(), поскольку он управляет дочерними элементами без интерфейсов.
Функция text() возвращает строки из набора QAccessible::Text для ползунка:
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); }
Функция slider() возвращает указатель на интерфейс QSlider. Для некоторых значений оставлена реализация родительского класса. Не все значения соответствуют всем объектам специальных возможностей, как вы можете видеть в случае QAccessible::Value. Вы должны вернуть пустую строку для тех значений, где соответствующий текст не может быть предоставлен.
Реализация функции role() очень простая:
QAccessible::Role QAccessibleSlider::role(int child) const { switch (child) { case PageLeft: case PageRight: return PushButton; case Position: return Indicator; default: return Slider; } }
Функция role должна быть переопределена для всех объектов и описывать роль себя и детей, которые не обеспечивают для себя интерфейсы специальных возможностей.
Далее, интерфейс специальных возможностей должен вернуть состояния, в которых может находиться ползунок. Рассмотрим часть реализации функции state(), чтобы показать, как обрабатывать всего несколько состояний:
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; }
Реализация функции state() в родительском классе использует реализацию QAccessibleInterface::state(). Мы просто должны отключить кнопки, если ползунок находится в минимуме или максимуме.
Теперь мы предоставляем информацию, которую мы знаем о ползунке, клиентам. Для того чтобы клиенты имели возможность изменять ползунок, например, его значение, мы должны предоставить информацию о действиях, которые могут быть выполнены, и выполнять их по запросу.. Мы обсудим это в следующем разделе.
QAccessible предоставляет ряд действий, которые могут быть выполнены по запросу клиентов. Если объект специальных возможностей поддерживает действия, следует переопределить следующие функции QAccessibleInterface:
Обратите внимание на то, что клиент может запросить любое действие от объекта. Если клиент не поддерживает действие, он возвращает false из doAction().
Ни одно из стандартных действий не принимает никаких параметров. Можно предоставить пользовательские действия, принимающие параметры. В этом случае интерфейс должен также переопределить userActionCount(). Так как это не определено в спецификации MSAA, то, вероятно, это будет полезно использовать только в том случае, если вы знаете, какие ВТ-клиенты будут использовать приложение.
QAccessibleInterface предоставляет клиентам другой метод для обработки объектов специальных возможностей. Он работает в целом так же, но использует понятие методов вместо действий. Доступные методы определены в перечислении QAccessible::Method. Следующие функции класса QAccessibleInterface должны быть переопределены, если объект специальных возможностей поддерживает методы:
Механизм действий, вероятно, будет заменен предоставлением методов вместо стандартных действий.
В качестве примеров того, как реализовать действия и методы, вы можете посмотреть реализации QAccessibleObject и QAccessibleWidget. Также вы можете взглянуть на документацию MSAA.
В этом разделе мы расскажем о процедуре реализации подключаемых модулей специальных возможностей для ваших интерфейсов. Подключаемый модуль - это класс, содержащийся в разделяемой библиотеке, которая может быть загружена во время выполнения. Это удобно для распространения интерфейсов с помощью подключаемых модулей, поскольку они будут загружаться только при необходимости.
Создание подключаемого модуля специальных возможностей достигается путем наследования QAccessiblePlugin, переопределения функций keys() и create() этого класса и добавления одного или двух макросов. Файл .pro должен быть изменен для использования шаблона подключаемого модуля, а библиотека, содержащая модуль, должна быть размещена в каталоге, в котором Qt ищет подключаемые модули специальных возможностей.
Мы пойдем путем реализации SliderPlugin, который является подключаемым модулем специальных возможностей и создает интерфейс для QAccessibleSlider, который мы реализовывали в примере QAccessibleWidget. Начнём с функции key():
QStringList SliderPlugin::keys() const { return QStringList() << "QSlider"; }
Мы просто должны вернуть имя класса единственного интерфейса, для которого наш подключаемый модуль может создать интерфейс специальных возможностей. Подключаемый модуль может поддерживать любое число классов; просто добавьте больше имен классов в список строк. Теперь мы переходим к функции create():
QAccessibleInterface *SliderPlugin::create(const QString &classname, QObject *object) { QAccessibleInterface *interface = 0; if (classname == "QSlider" && object && object->isWidgetType()) interface = new AccessibleSlider(classname, static_cast<QWidget *>(object)); return interface; }
Мы проверяем, что интерфейс, который запрашивается, это QSlider; если это так, то мы создаем и возвращаем интерфейс для него. Обратите внимание на то, что объект всегда будет экземпляром класса classname. Вы должны вернуть 0, если вы не поддерживаете этот класс. updateAccessibility() проверяет доступные подключаемые модули специальных возможностей, пока не найдет тот, который возвращает не 0.
В заключение вам необходимо включить в файл cpp макросы:
Q_EXPORT_STATIC_PLUGIN(SliderPlugin) Q_EXPORT_PLUGIN2(acc_sliderplugin, SliderPlugin)
Макрос Q_EXPORT_PLUGIN2 экспортирует подключаемый модуль в классе SliderPlugin в библиотеку acc_sliderplugin. Первым аргументом является имя файла библиотеки подключаемых модулей, исключая суффикс, а вторым - имя класса. Для получения дополнительной информации о подключаемых модулях обратитесь к обзорному документу по подключаемым модулям.
Вы можете пропустить первый макрос, если вы не хотите, чтобы подключаемый модуль быть статически слинкован с приложением.
Если вы не хотите предоставлять подключаемые модули для интерфейсов специальных возможностей, можно использовать интерфейс фабрики (QAccessible::InterfaceFactory), который является рекомендуемым способом обеспечения интерфейсов специальных возможностей в статически слинкованных приложениях.
Фабрика является указателем на функцию, принимающую те же параметры, что и функция create() класса QAccessiblePlugin - QString и QObject. Она работает таким же образом. Вы устанавливаете фабрику функцией installFactory (). Приведём пример того, как создать фабрику для класса SliderPlugin:
QAccessibleInterface *sliderFactory(const QString &classname, QObject *object) { QAccessibleInterface *interface = 0; if (classname == "QSlider" && object && object->isWidgetType()) interface = new SliderInterface(classname, static_cast<QWidget *>(object)); return interface; } int main(int argv, char **args) { QApplication app(argv, args); QAccessible::installFactory(sliderFactory); ... }
В документе Кросс-платформенная поддержка специальных возможностей в Qt 4 содержится более общий обзор функций специальных возможностей Qt и обсуждается, как они используются на каждой платформе. проблемы
Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies) | Торговые марки | Qt 4.5.3 |
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |