QWidgetアプリケーションのアクセシビリティ

はじめに

ここでは、Qtアクセシビリティ・インターフェイスQAccessibleInterface と、アプリケーションをアクセシブルにする方法に焦点を当てます。

QWidgetベースのアプリケーションにおけるアクセシビリティ

支援技術と通信する場合、支援技術が理解できる方法でQtのユーザーインターフェイスを記述する必要があります。Qtアプリケーションは、QAccessibleInterface 、個々のUI要素に関する情報を公開します。現在、Qtはウィジェットとウィジェットパーツ、例えばスライダーハンドルのサポートを提供していますが、必要であれば、QObjectQAccessible には、UIを記述する列挙型が含まれています。列挙型については、このドキュメントの中で検討していく。

UIの構造は、QAccessibleInterface サブクラスのツリーとして表されます。これは多くの場合、アプリケーションのUIを構成するQWidgetsの階層を反映したものです。

サーバーはupdateAccessibility ()を通じて、イベントを送信することでオブジェクトの変更をクライアントに通知し、クライアントはイベントを受信するために登録します。利用可能なイベントは、QAccessible::Event enumによって定義されます。クライアントは、QAccessible::queryAccessibleInterface() を介して、イベントを生成したオブジェクトを問い合わせることができる。

QAccessible のメンバと列挙型は、アクセス可能なオブジェクトを記述するために使用される:

  • Role:オブジェクトがユーザーインターフェースで果たす役割を記述する。例えば、ウィンドウ、テキスト編集、テーブルのセルなどである。
  • Relation:オブジェクト階層におけるオブジェクト間の関係を記述します。
  • State:オブジェクトは様々な状態になり得ます。状態の例としては、オブジェクトが無効になっているかどうか、フォーカスがあるかどうか、ポップアップメニューがあるかどうかなどがあります。

例えば、ボタンのテキストなどです。オブジェクトは、QAccessible::Text enumで定義された文字列を提供し、コンテンツに関する情報を提供します。

アクセス可能なオブジェクト・ツリー

前述のように、ツリー構造はアプリケーションのアクセス可能なオブジェクトから構築されます。ツリーをナビゲートすることで、クライアントはUIのすべての要素にアクセスできます。オブジェクトの関係は、クライアントにUIに関する情報を与えます。例えば、スライダーのハンドルは、それが属するスライダーの子です。QAccessible::Relation 、クライアントがオブジェクトに求めることができる様々な関係について説明します。

QtQObject ツリーとアクセス可能なオブジェクトツリーの間には、直接的なマッピングはないことに注意してください。例えば、スクロールバーのハンドルはアクセス可能なオブジェクトですが、Qtのウィジェットやオブジェクトではありません。

ATクライアントは、ツリーのルート・オブジェクトであるQApplication を通して、アクセシビリティ・オブジェクト・ツリーにアクセスすることができます。QAccessibleInterface::parent(),QAccessibleInterface::childCount(),QAccessibleInterface::child() 関数を使って、ツリーを移動することができます。

Qtは、ウィジェットとQtクイックコントロールにアクセシブルなインタフェースを提供します。QAccessible::queryInterface() によって、QObject のサブクラスのインターフェイスを要求することができます。より特殊なインターフェースが定義されていない場合は、デフォルトの実装が提供されます。AT-Clientは、同等のQObject 、例えばスクロールバーハンドルを持たないアクセシブルオブジェクトのインタフェースを取得することはできませんが、親アクセシブルオブジェクトのインタフェースを介して通常のオブジェクトとして表示され、例えば、QAccessibleInterface::relations ()でそれらの関係を問い合わせることができます。

説明のために、アクセシブル・オブジェクト・ツリーの画像を示します。ツリーの下には、オブジェクトの関係の例が表になっています。

ラベルは上から順に、QAccessibleInterface クラス名、インターフェイスが提供されているウィジェット、オブジェクトのRole です。Position、PageLeft、PageRightはそれぞれ、スライダーハンドル、スライダー溝左、スライダー溝右に対応します。これらのアクセス可能なオブジェクトには、同等のQObject がありません。

ソースオブジェクトターゲット オブジェクト関係
スライダーインジケータコントローラー
インジケータスライダー制御
スライダーアプリケーション祖先
アプリケーションスライダー
プッシュボタンインジケーター兄弟

静的QAccessible関数

アクセシビリティは、QAccessible の静的関数によって管理されます。これらの関数は、QAccessible インターフェイスを生成し、オブジェクトツリーを構築し、MSAA やその他のプラットフォーム固有のテクノロジーとの接続を開始します。アプリケーションをアクセシブルにする方法だけに興味があるのであれば、このセクションはアクセシビリティの実装まで読み飛ばしてかまいません。

クライアントとサーバー間の通信は、setRootObject ()が呼び出されたときに開始されます。これは、QApplication インスタンスがインスタンス化されたときに行われます。

QObjectupdateAccessibility() を呼び出すと、イベントをリッスンしているクライアントに変更が通知される。この関数は、イベントを支援技術にポストするために使用され、アクセシブルなeventsupdateAccessibility() によってポストされます。

queryAccessibleInterface QObject(Qtのすべてのウィジェットはインタフェースを提供します。他のQObject サブクラスの動作を制御するインタフェースが必要な場合は、QAccessibleObject 便利なクラスが機能の一部を実装してくれますが、自分でインタフェースを実装する必要があります。

QObjects のアクセシビリティ・インターフェースを生成するファクトリーは、QAccessible::InterfaceFactory 型の関数です。複数のファクトリーをインストールすることができます。最後にインストールされたファクトリーが、最初にインターフェースを要求されます。queryAccessibleInterface() はファクトリーを使用して、QObjectのインターフェースを作成します。通常、インターフェースを生成するプラグインを実装することができるので、ファクトリーについて気にする必要はありません。後で両方のアプローチの例を示します。

アクセシビリティの実装

ウィジェットや他のユーザーインターフェイス要素にアクセシビリティサポートを提供するには、QAccessibleInterface を実装し、QAccessiblePlugin で配布する必要があります。アプリケーションにインターフェイスをコンパイルし、そのためのQAccessible::InterfaceFactory を提供することも可能です。ファクトリーは、静的にリンクする場合や、プラグインの複雑さを増やしたくない場合に使用できます。これは、例えば3rdパーティのライブラリを提供する場合に有利になります。

すべてのウィジェットやその他のユーザーインターフェイス要素は、インターフェイスとプラグインを持つべきです。アプリケーションでアクセシビリティをサポートしたい場合、以下のことを考慮する必要があります:

  • Qtはすでに自身のウィジェットに対してアクセシビリティを実装しています。したがって、可能な限りQtウィジェットを使用することをお勧めします。
  • アクセシビリティ・クライアントが利用できるようにしたい各要素には、QAccessibleInterface を実装する必要があります。
  • 実装したカスタム・ユーザー・インターフェース要素からアクセシビリティ・イベントを送信する必要があります。

一般的に、Qt のアクセシビリティサポートが元々構築されている MSAA にある程度慣れていることをお勧めします。また、QAccessible の列挙値についても勉強してください。この列挙値には、考慮する必要のある役割、アクション、関係、イベントが記述されています。

Qt のウィジェットがどのようにアクセシビリティを実装しているかを調べることもできます。MSAA標準の大きな問題の1つは、インタフェースがしばしば一貫性のない方法で実装されることです。これは、クライアントの生活を困難にし、しばしばオブジェクトの機能を推測することにつながります。

QAccessibleInterface を継承し、その純粋仮想関数を実装することで、インターフェースを実装することは可能です。しかし、実際には、QAccessibleObjectQAccessibleWidget を継承して、機能の一部を実装する方が望ましいでしょう。次のセクションでは、QAccessibleWidget クラスを継承して、ウィジェットのアクセシビリティを実装する例を示します。

QAccessibleObject および QAccessibleWidget 便利クラス

ウィジェット用のアクセシビリティ・インターフェースを実装する場合、原則として、ウィジェット用の便宜クラスであるQAccessibleWidget を継承します。もう1つの利用可能な便宜クラスは、QAccessibleWidget によって継承されるQAccessibleObject で、これは QObjects 用のインターフェースの一部を実装しています。

QAccessibleWidget は以下の機能を提供します:

  • ツリーのナビゲーションとオブジェクトのヒット・テストを処理します。
  • すべてのQWidgetに共通するイベント、ロール、およびアクションを処理します。
  • すべてのウィジェットで実行できるアクションとメソッドを処理します。
  • rect() で外接矩形を計算します。
  • 一般的なウィジェットに適したtext() 文字列を与えます。
  • すべてのウィジェットに共通なstates を設定します。

QAccessibleWidget の例

カスタムウィジェットを作成し、そのためのインタフェースを実装する代わりに、Qt の標準ウィジェットの 1 つであるQSlider に対して、アクセシビリティがどのように実装されるかを示します。アクセシブルなインターフェイスである QAccessibleSlider は QAccessibleAbstractSlider を継承しており、QAccessibleAbstractSlider はQAccessibleWidget を継承しています。このセクションを読むために QAccessibleAbstractSlider クラスを調べる必要はありません。もし見たいのであれば、Qt の全てのアクセシブルインターフェイスのコードは qtbase/src/widgets/accessible にあります。ここに QAccessibleSlider のコンストラクタがあります:

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

スライダーは複雑なコントロールで、アクセス可能な子オブジェクトのController として機能します。この関係は、インターフェイス(parent()、child()、relations())によって知られていなければなりません。これは、QAccessibleWidget によって提供されるメカニズムである制御シグナルを使って行うことができます。これはコンストラクタで行う:

このように宣言されたシグナルにはすべて同じ原則が適用されます。シグナル名が正しく指定されていることを確認するために、QLatin1String

アクセシブル・オブジェクトが、ユーザーが知る必要のある方法で変更されると、アクセシブル・インターフェースを介してクライアントにイベントを送信し、変更を通知します。このように、QSlider 、値が変更されたことを示すためにupdateAccessibility ()を呼び出す:

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

クライアントがイベントを受信した直後に新しい値を問い合わせる可能性があるため、この呼び出しはスライダーの値が変更された後に行われることに注意してください。

インターフェイスは、それ自身と、それ自身のインターフェイスを提供しない子の外接矩形を計算できなければならない。QAccessibleSlider には、SliderElements という private enum で識別されるそのような子が3つあり、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);
    }
    ...

関数の最初の部分は省略しましたが、スライダーハンドルの外接矩形を計算するために現在のstyle を使用しています。これはsrect に格納されています。上のコードでデフォルトのケースでカバーされている子0はスライダーそのものなので、単純にスーパークラスから取得した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関数はすべてのオブジェクトによって再実装されるべきで、それ自身と、それ自身のアクセシブルインターフェースを提供しない子オブジェクトの役割を記述します。

次に、アクセシブル・インターフェイスは、スライダーが存在できるstates を返す必要があります。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 ()の実装を使用している。単に、スライダーが最小か最大になったらボタンを無効にするだけです。

これで、スライダーに関する情報をクライアントに公開しました。クライアントがスライダーを変更できるようにするには、例えば値を変更するには、実行可能なアクションに関する情報を提供し、要求に応じて実行する必要があります。これについては次のセクションで説明します。

クライアントからのアクションリクエストの処理

アプリケーションは、クライアントによって呼び出されるアクションを公開することができます。オブジェクトでアクションをサポートするには、QAccessibleActionInterface を継承します。

インタラクティブな要素は、例えばマウス操作によってトリガーされる機能を公開する必要があります。例えば、ボタンはクリックアクションを実装する必要があります。

フォーカスの設定も、フォーカスを受け取るウィジェットに対して実装されるべきアクションです。

オブジェクトがサポートするすべてのアクションのリストを返すには、actionNames()を再実装する必要があります。このリストはローカライズしてはいけません。

ローカライズされた文字列を返す必要があるアクションに関する情報を提供する2つの関数があります:localizedActionName()とlocalizedActionDescription()。これらの関数は、ユーザーにアクションを提示するためにクライアントが使用することができます。一般的に、名前は簡潔であるべきで、"press "のような単一の単語のみから構成されるべきです。

標準的なアクション名とローカライゼーションのリストが用意されており、アクションが適合するときに使用する。これによって、クライアントがセマンティクスを理解しやすくなり、Qtは異なるプラットフォームでそれらを正しく公開しようとします。

もちろん、アクションをトリガーする方法も必要です。doAction()は、名前と説明に従ってアクションを呼び出す必要があります。

アクションやメソッドの実装例を見るには、QAccessiblePushButtonのようなQtの標準ウィジェットの実装を調べるとよいでしょう。

アクセシブル・プラグインの実装

このセクションでは、あなたのインターフェースにアクセシブルなプラグインを実装する手順を説明します。プラグインとは、共有ライブラリに格納され、実行時にロードできるクラスのことです。インターフェイスをプラグインとして配布すると、必要なときだけ読み込まれるので便利です。

アクセシブルなプラグインを作成するには、QAccessiblePlugin を継承し、プラグインの JSON 記述でサポートされるクラス名を定義し、QAccessiblePlugin からcreate() を再実装します。.pro ファイルはプラグインテンプレートを使用するように変更する必要があり、プラグインを含むライブラリは Qt がアクセシブルなプラグインを検索するパスに配置する必要があります。

QAccessibleWidget ExampleからQAccessibleSliderインターフェイスを生成するアクセシブル・プラグインであるSliderPluginkey() 関数から始めます:

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

プラグインがアクセシブルなインターフェイスを作成できる単一のインターフェイスのクラス名を返す必要があります。プラグインは任意の数のクラスをサポートできます; 文字列リストにクラス名を追加するだけです。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;
}

要求されたインターフェイスがQSlider のものであるかどうかをチェックし、もしそうであれば、そのインターフェイスを作成して返します。object は常にclassname のインスタンスであることに注意してください。 クラスをサポートしていない場合は、0を返さなければなりません。updateAccessibility()は、0を返さないプラグインが見つかるまで、利用可能なアクセシビリティ・プラグインをチェックします。

最後に、cppファイルにマクロをインクルードする必要があります:

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

Q_PLUGIN_METADATA マクロは、SliderPlugin クラスのプラグインをacc_sliderplugin ライブラリにエクスポートします。第1引数はプラグインのIIDで、第2引数はプラグインのメタデータ情報を保持するjsonファイル(オプション)です。プラグインの詳細については、プラグインの概要を参照してください。

プラグインをアプリケーションと静的にリンクするか、動的にリンクするかは問いません。

インターフェース・ファクトリの実装

アクセシビリティ・インターフェイスにプラグインを提供したくない場合、静的にリンクされたアプリケーションでアクセシビリティ・インターフェイスを提供する推奨の方法である、インターフェイス・ファクトリー(QAccessible::InterfaceFactory)を使用することができます。

ファクトリーは、QAccessiblePlugincreate() と同じパラメータ、つまりQStringQObject を受け取る関数の関数ポインタです。 また、同じように動作します。installFactory() 関数でファクトリーをインストールします。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

QMLアイテムのアクセシビリティを可能にする

QAccessible

アクセシビリティに関連する列挙型および静的関数

QAccessibleActionInterface

インターフェイスの呼び出し可能なアクションのサポートを実装する。

QAccessibleAnnouncementEvent

支援技術による所定のメッセージのアナウンスを要求するために使用されます。

QAccessibleAttributesInterface

アクセシブルなオブジェクトの属性を報告するためのサポートを実装しています。

QAccessibleEditableTextInterface

編集可能なテキストを持つオブジェクトのサポートを実装しています。

QAccessibleEvent

アクセシビリティ通知の基本クラス

QAccessibleInterface

アクセシブルなオブジェクトに関する情報を公開するインタフェースを定義します。

QAccessibleObject

QAccessibleInterfaceの一部をQObjectsに実装します。

QAccessiblePlugin

ユーザー・インターフェース要素のアクセシビリティ情報を提供するプラグインのための抽象ベース・クラス

QAccessibleSelectionInterface

選択処理のサポートを実装しています。

QAccessibleStateChangeEvent

オブジェクトの状態が変更されたことをアクセシビリティ・フレームワークに通知します。

QAccessibleTableCellInterface

IAccessibleTable2 Cell インターフェースのサポートを実装します。

QAccessibleTableInterface

IAccessibleTable2 インターフェースのサポートを実装します。

QAccessibleTableModelChangeEvent

セルが追加または削除されたテーブル、リスト、またはツリーの変更を示す。変更が行数に影響した場合、firstColumn と lastColumn は -1 を返す。同様に、列の場合、行関数は -1 を返す。

QAccessibleTextCursorEvent

カーソル移動の通知

QAccessibleTextInsertEvent

テキスト挿入の通知

QAccessibleTextInterface

テキスト処理のサポートを実装

QAccessibleTextRemoveEvent

テキストの削除を通知

QAccessibleTextSelectionEvent

オブジェクトのテキスト選択の変更を知らせる

QAccessibleTextUpdateEvent

テキストの変更を通知します。これは、行編集のような編集可能なテキストをサポートするアクセシブルのためのものです。このイベントは、例えば、選択されたテキストの一部が新しいテキストの貼り付けによって置換されたときや、エディタのオーバーライドモードで発生します。

QAccessibleValueChangeEvent

アクセシブルオブジェクトの値の変更を記述します。

QAccessibleValueInterface

値を操作するオブジェクトのサポートを実装します。

QAccessibleWidget

QWidgets用のQAccessibleInterfaceの実装

©2024 The Qt Company Ltd. 本ドキュメントに含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。