QWidgetアプリケーションのアクセシビリティ
はじめに
ここでは、Qt のアクセシビリティインターフェースである `QAccessibleInterface ` と、アプリケーションをアクセシブルにする方法に焦点を当てます。
QWidget ベースのアプリケーションにおけるアクセシビリティ
支援技術と通信する際には、支援技術が理解できる形で Qt のユーザーインターフェースを記述する必要があります。 Qtアプリケーションは、個々のUI要素に関する情報を公開するためにQAccessibleInterface を使用します。現在、Qtはウィジェットおよびウィジェットの構成要素(例:スライダーのハンドル)に対するサポートを提供していますが、必要に応じて、任意のQObject に対してこのインターフェースを実装することも可能です。QAccessible には、UIを記述する列挙型が定義されています。本ドキュメントでは、これらの列挙型について詳しく検討していきます。
UIの構造は、QAccessibleInterface のサブクラスからなるツリーとして表現されます。これは多くの場合、アプリケーションのUIを構成するQWidgetの階層構造を反映したものです。
サーバーは、updateAccessibility() を通じてイベントを送信することでオブジェクトの変更をクライアントに通知し、クライアントはイベントを受信するために登録を行います。利用可能なイベントは、QAccessible::Event 列挙型によって定義されています。その後、クライアントはQAccessible::queryAccessibleInterface() を通じて、そのイベントを生成したオブジェクトを照会することができます。
QAccessible 内のメンバおよび列挙型は、アクセス可能なオブジェクトを記述するために使用されます:
- Role: オブジェクトがユーザーインターフェースにおいて果たす役割(ウィンドウ、テキスト編集フィールド、テーブルのセルなど)を記述します。
- Relation: オブジェクト階層におけるオブジェクト間の関係を記述します。
- State: オブジェクトはさまざまな状態をとることができます。状態の例としては、オブジェクトが無効になっているか、フォーカスを持っているか、ポップアップメニューを提供しているかなどがあります。
クライアントには、オブジェクトの内容(例:ボタンのテキスト)を取得する手段もいくつか用意されています。オブジェクトは、QAccessible::Text 列挙型で定義された文字列を提供し、それによって内容に関する情報を提供します。
アクセシブル・オブジェクト・ツリー
前述のように、アプリケーションのアクセシブルオブジェクトからツリー構造が構築されます。クライアントはこのツリーをナビゲートすることで、UI内のすべての要素にアクセスできます。オブジェクト間の関係は、クライアントにUIに関する情報を提供します。例えば、スライダーのハンドルは、それが属するスライダーの子要素です。QAccessible::Relation は、クライアントがオブジェクトに問い合わせることができる様々な関係を記述しています。
QObject なお、Qt XML-ph-0000@deepl.internalツリーとアクセシビリティ・オブジェクト・ツリーの間には、直接的な対応関係はありません。例えば、スクロールバーのハンドルはアクセシビリティ・オブジェクトですが、Qtにおけるウィジェットやオブジェクトではありません。
ATクライアントは、ツリーのルートオブジェクトであるQApplication を通じて、アクセシビリティオブジェクトツリーにアクセスできます。クライアントは、QAccessibleInterface::parent()、QAccessibleInterface::childCount()、およびQAccessibleInterface::child()関数を使用して、ツリー内を移動することができます。
Qt WidgetsおよびQt Quick コントロールに対してアクセシビリティインターフェースを提供しています。QObject のサブクラスに対するインターフェースは、QAccessible::queryInterface()を通じて要求できます。より特殊なインターフェースが定義されていない場合は、デフォルトの実装が提供されます。 ATクライアントは、QObject に相当するものが存在しないアクセシブルオブジェクト(例:スクロールバーのハンドル)のインターフェースを取得することはできませんが、それらのオブジェクトは親のアクセシブルオブジェクトのインターフェースを通じて通常のオブジェクトとして表示されます。例えば、QAccessibleInterface::relations() を使用してそれらの関係性を照会することができます。
これを説明するために、アクセシブルオブジェクトツリーの図を示します。ツリーの下には、オブジェクト間の関係の例を示す表があります。

上から順に、QAccessibleInterface のクラス名、インターフェースが提供されているウィジェット、およびオブジェクトのRole がラベルとして表示されています。Position、PageLeft、PageRightは、それぞれスライダーのハンドル、スライダーの溝(左側)、スライダーの溝(右側)に対応しています。これらのアクセシブルオブジェクトには、同等のQObject が存在しません。
| ソースオブジェクト | ターゲットオブジェクト | 関係 |
|---|---|---|
| スライダー | インジケータ | コントローラ |
| インジケーター | スライダー | 制御対象 |
| スライダー | アプリケーション | Ancestor |
| アプリケーション | スライダー | 子 |
| プッシュボタン | インジケーター | 兄弟 |
QAccessibleの静的関数
アクセシビリティは、QAccessible の静的関数によって管理されており、これについては後ほど詳しく説明します。これらの関数は、QAccessible インターフェースを生成し、オブジェクトツリーを構築し、MSAAやその他のプラットフォーム固有の技術との接続を開始します。アプリケーションをアクセシブルにする方法のみを知りたい場合は、このセクションを飛ばして「アクセシビリティの実装」のセクションに進んでも問題ありません。
クライアントとサーバー間の通信は、setRootObject() が呼び出されたときに開始されます。これはQApplication インスタンスがインスタンス化される際に自動的に行われるため、開発者が手動で行う必要はありません。
QObject がupdateAccessibility()を呼び出すと、イベントをリッスンしているクライアントにその変更が通知されます。この関数は、支援技術にイベントを送信するために使用され、アクセシビリティ対応のevents はupdateAccessibility()によって送信されます。
queryAccessibleInterface()は、QObjectに対するアクセシビリティインターフェースを返します。Qt Widgetsのすべてのウィジェットはインターフェースを提供しています。他のQObject サブクラスの動作を制御するためのインターフェースが必要な場合は、QAccessibleObject という利便性クラスが機能の一部を実装していますが、インターフェースを自身で実装する必要があります。
QObject用のアクセシビリティインターフェースを生成するファクトリは、QAccessible::InterfaceFactory 型の関数です。複数のファクトリをインストールすることが可能です。最後にインストールされたファクトリが、インターフェースの要求に対して最初に呼び出されます。queryAccessibleInterface()は、これらのファクトリを使用してQObject用のインターフェースを作成します。通常、インターフェースを生成するプラグインを実装できるため、ファクトリについて気にする必要はありません。 後ほど、両方のアプローチの例を示します。
アクセシビリティの実装
ウィジェットやその他のユーザーインターフェース要素にアクセシビリティサポートを提供するには、QAccessibleInterface を実装し、それをQAccessiblePlugin として配布する必要があります。また、インターフェースをアプリケーションにコンパイルして組み込み、それに対応するQAccessible::InterfaceFactory を提供することも可能です。 静的リンクを行う場合や、プラグインによる複雑さを避けたい場合には、ファクトリを使用できます。これは、たとえばサードパーティ製ライブラリを提供する場合などに有利です。
すべてのウィジェットやその他のユーザーインターフェース要素には、インターフェースとプラグインを用意する必要があります。アプリケーションでアクセシビリティをサポートしたい場合は、以下の点を考慮する必要があります。
- Qtは、独自のウィジェットに対してすでにアクセシビリティを実装しています。したがって、可能な限りQt Widgetsを使用することをお勧めします。
- アクセシビリティクライアントから利用可能にしたい各要素について、QAccessibleInterface を実装する必要があります。
- 実装したカスタムユーザーインターフェース要素から、アクセシビリティイベントを送信する必要があります。
一般に、Qtのアクセシビリティサポートが当初構築された基盤であるMSAAについて、ある程度理解しておくことをお勧めします。また、考慮すべき役割、アクション、関係性、およびイベントを記述したQAccessible の列挙型値についても学習する必要があります。
なお、Qt Widgetsがアクセシビリティをどのように実装しているかを確認することができます。MSAA標準の大きな問題の一つは、インターフェースの実装がしばしば一貫性を欠いていることです。これによりクライアント側の作業が困難になり、オブジェクトの機能について推測を迫られることがよくあります。
QAccessibleInterface を継承し、その純仮想関数を実装することで、インターフェースを実装することは可能です。しかし実際には、機能の一部がすでに実装されているQAccessibleObject やQAccessibleWidget を継承する方が望ましい場合がほとんどです。次のセクションでは、QAccessibleWidget クラスを継承してウィジェットのアクセシビリティを実装する例を見ていきます。
QAccessibleObject および QAccessibleWidget 便利クラス
ウィジェットのアクセシビリティインターフェースを実装する際は、原則として、ウィジェット用の利便性クラスであるQAccessibleWidget を継承します。もう1つの利用可能な利便性クラスとして、QAccessibleWidget が継承しているQAccessibleObject があり、これはQObject向けのインターフェースの一部を実装しています。
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` で識別される 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 Widgets の標準ウィジェットの実装を参照するとよいでしょう。
アクセシブルプラグインの実装
このセクションでは、インターフェース用のアクセシブルプラグインを実装する手順について説明します。プラグインとは、実行時に読み込める共有ライブラリに格納されたクラスのことです。インターフェースは必要なときにのみ読み込まれるため、プラグインとして配布すると便利です。
アクセシブルプラグインの作成は、QAccessiblePlugin を継承し、プラグインのJSON記述でサポートするクラス名を定義し、QAccessiblePlugin のcreate()を再実装することで実現されます。.pro ファイルは、プラグインテンプレートを使用するように変更する必要があり、プラグインを含むライブラリは、Qtがアクセシブルプラグインを検索するパス上に配置する必要があります。
ここでは、SliderPlugin の実装について解説します。これは、QAccessibleWidget の例から QAccessibleSlider インターフェースを生成するアクセシブルプラグインです。まず、key() 関数から見ていきましょう。
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 ライブラリにエクスポートします。最初の引数はプラグインのIID、2番目の引数はプラグインのメタデータ情報を格納するオプションのJSONファイルです。プラグインの詳細については、プラグインの概要ドキュメントを参照してください。
プラグインをアプリケーションに静的リンクするか動的リンクするかは問いません。
インターフェースファクトリの実装
アクセシビリティインターフェース用のプラグインを提供したくない場合は、インターフェースファクトリ(QAccessible::InterfaceFactory )を使用できます。これは、静的リンクされたアプリケーションでアクセシビリティインターフェースを提供するための推奨される方法です。
ファクトリとは、QAccessiblePlugin のcreate() と同じパラメータ(QString およびQObject )を受け取る関数への関数ポインタです。動作も同様です。ファクトリは、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);
...
}関連クラス
QMLアイテムのアクセシビリティを有効にします | |
アクセシビリティに関連する列挙型と静的関数 | |
インターフェースにおける呼び出し可能なアクションのサポートを実装 | |
支援技術に対して、指定されたメッセージの読み上げを要求するために使用されます | |
アクセシビリティ対応オブジェクトの属性報告機能を実装します | |
編集可能なテキストを持つオブジェクトのサポートを実装します | |
アクセシビリティ通知の基底クラス | |
アクセシブルなオブジェクトに関する情報を公開するインターフェースを定義します | |
QObject 向けの QAccessibleInterface の一部を実装します | |
ユーザーインターフェース要素のアクセシビリティ情報を提供するプラグインのための抽象基底クラス | |
選択処理のサポートを実装 | |
オブジェクトの状態が変更されたことをアクセシビリティフレームワークに通知する | |
IAccessibleTable2 Cell インターフェースのサポートを実装します | |
IAccessibleTable2 インターフェースのサポートを実装します | |
セルが追加または削除されたテーブル、リスト、またはツリーの変更を表します。変更が複数の行に影響した場合、firstColumn および lastColumn は -1 を返します。同様に、列についても、行に関する関数は -1 を返す場合があります | |
カーソルの移動を通知します | |
テキストの挿入を通知します | |
テキスト処理のサポートを実装します | |
テキストの削除を通知します | |
オブジェクトのテキスト選択範囲の変更を通知します | |
テキストの変更を通知します。これは、ラインエディットなど、編集可能なテキストをサポートするアクセシブル向けです。このイベントは、たとえば、選択されたテキストの一部が新しいテキストの貼り付けによって置き換えられた場合や、エディタのオーバーライドモード時に発生します | |
アクセシブルオブジェクトの値の変更を記述します | |
値を操作するオブジェクトへの対応を実装します | |
ビューポートのサポートを実装します | |
QWidget 向けの QAccessibleInterface を実装します |
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.