Version: 2021.3
言語: 日本語
Dispatching events
Synthesizing events

イベントの処理

UI Toolkit のイベントは、HTML イベント に似ています。イベントが発生すると、ビジュアル要素ツリーの伝搬経路に沿って送信されます。イベントは対象となるビジュアル要素だけでなく、伝搬経路内のすべての要素に送信されます。

イベント処理の流れは以下の通りです。

  1. ルート要素からイベントターゲットの親までの要素にイベントコールバックを実行する。これはディスパッチプロセスの 下降段階 です。
  2. イベントターゲットでイベントコールバックを実行します。これはディスパッチ処理の ターゲット段階 です。
  3. イベントターゲットで ExecuteDefaultActionAtTarget() を呼び出します。
  4. イベントターゲットの親からルートまでの要素のイベントコールバックを実行します。これはディスパッチプロセスの 上昇段階 です。
  5. ExecuteDefaultAction() をイベントターゲット上で呼び出します。

イベントが伝搬経路を移動すると、Event.currentTarget プロパティは、現在そのイベントを処理する要素に更新されます。イベントコールバック関数内では、以下の通りです。

  • Event.currentTarget は、コールバックが登録されるビジュアル要素です。
  • Event.target は、元のイベントが発生するビジュアル要素です。

詳しくは、イベントのディスパッチ を参照してください。

イベントコールバックを登録する

イベントコールバックを登録すると、テキストラベル上でマウスをクリックしたときの動作など、既存クラスの個々のインスタンスの動作をカスタマイズできます。

伝搬経路上の各要素 (ターゲットを除く) は、イベントを 2 回受け取ることができます。

  • 降下段階で 1 度。
  • 上昇段階で 1 度

デフォルトでは、登録されたコールバックは、ターゲットフェーズとバブルアップフェーズの間に実行されます。このデフォルトの動作により、親要素が子要素の後に反応するようになります。例えば、親要素が子要素より先に反応するようにしたい場合は、 TrickleDown.TrickleDown オプションでコールバックを登録します。

// 降下段階のコールバックを登録
myElement.RegisterCallback<MouseDownEvent>(MyCallback, TrickleDown.TrickleDown);

これは、ディスパッチャーに、ターゲット段階と降下段階でコールバックを実行するように通知します。

カスタム動作を特定のビジュアル要素に加えるには、イベントのコールバックを登録する必要があります。例えば、以下のコードは MouseDownEvent のコールバックを登録します。

// マウスダウンイベントのコールバックの登録
myElement.RegisterCallback<MouseDownEvent>(MyCallback);

コールバックの署名は以下のようになります。

void MyCallback(MouseDownEvent evt) { /* ... */ }

1 つのイベントに対して複数のコールバックを登録することができます。同じコールバック関数を登録できるのは、同じイベントと同じプロパゲーションフェーズに 1 度だけです。VisualElement からコールバックを削除するには、myElement.UnregisterCallback() メソッドを呼び出します。

Send custom data to an event callback

イベントのコールバックと一緒にカスタムデータを送ることができます。カスタムデータを添付するには、呼び出しを拡張してコールバックを登録する必要があります。

以下のコードでは、MouseDownEvent のコールバックを登録し、カスタムデータをコールバック関数に送信しています。

// ユーザーデータをコールバックとともに送信
myElement.RegisterCallback<MouseDownEvent, MyType>(MyCallbackWithData, myData);

コールバック関数は、この署名を返します。

void MyCallbackWithData(MouseDownEvent evt, MyType data) { /* ... */ }

コントロールの入力イベントを処理する

入力イベントを処理するために、イベントハンドラーを使用するか、マニピュレーターを使用することができます。

ポインターをキャプチャする

ポインターの入力を処理する場合、コントロールにポインターをキャプチャさせたい場合があります。ビジュアル要素がポインターをキャプチャすると、ポインターがビジュアル要素上にあるかどうかにかかわらず、Unity はポインターに関連するすべてのイベントをビジュアル要素に送信します。例えば、ドラッグイベントを受信するコントロールを作成し、ポインターをキャプチャすると、コントロールはポインターの位置に関係なくドラッグイベントを受信します。

ポインターをキャプチャするには、キャプチャイベント を使用します。例は、カスタムエディターウィンドウ内にドラッグアンドドロップ UI を作成する を参照してください。

マニピュレーターでイベントを処理する

イベントロジックを UI コードから分離したい場合は、マニピュレーターを使用してイベントを処理します。マニピュレーター は、イベントコールバックの保存、登録、登録解除を行う専用のクラスです。UI Toolkit がサポートするマニピュレーターのいずれかを使用または継承して、イベントを処理することができます。

UI Toolkit は、以下のマニピュレーターをサポートします。

マニピュレーター 継承 説明 
Manipulator 提供されるすべてのマニピュレーターの基本クラスです。
KeyboardNavigationManipulator Manipulator デバイス固有の入力イベントを、キーボードによるより高度なナビゲーション操作に変換する処理を行います。
MouseManipulator Manipulator マウス入力を処理します。起動時フィルターのリストを持っています。
ContextualMenuManipulator MouseManipulator ユーザーがマウスの右ボタンをクリックするか、キーボードのメニューキーを押すと、コンテキストメニューが表示されます。
PointerManipulator MouseManipulator ポインターの入力を処理します。起動時フィルターのリストを持っています。
Clickable PointerManipulator 要素上のマウスイベントを追跡し、ポインターが要素上にあるときにユーザーがマウスボタンをクリックすると、コールバックします。

カスタムコントロールでイベントに応答する

カスタムコントロールを実装している場合、UI Toolkit のイベントに 2 つの方法で応答することができます。

  • イベントコールバックの登録
  • デフォルトアクションの実装

イベントに対してどのように対応するかは、状況によって異なります。

コールバックとデフォルトアクションの違いは以下の通りです。

  • コールバックはクラスのインスタンスに登録する必要があります。デフォルトアクションは、クラスの仮想関数として実行されます。
  • コールバックは、伝搬経路上のすべてのビジュアル要素に対して実行されます。デフォルトのアクションは、イベントターゲットに対してのみ実行されます。
  • コールバックは、イベントに反応すべきかどうかを判断するために、追加確認を行う場合があります。例えば、マウスのクリックを処理するコールバックは、その要素がイベントのターゲットであるかどうかを確認する場合があります。デフォルトのアクションはこの手順を省略できます。
  • デフォルトアクションは伝搬段階でコールバックレジストリの検索を必要としないため、パフォーマンス面で若干有利です。

デフォルトアクションの実装

デフォルトアクションは、クラスのすべてのインスタンスに適用されます。デフォルトアクションを実装するクラスは、そのインスタンスにコールバックを登録することもできます。

クラスにデフォルトのアクションを実装する場合、VisualElement の新しいサブクラスを派生させ、ExecuteDefaultActionAtTarget() メソッドか ExecuteDefaultAction() メソッドのいずれか、または両方を実装する必要があります。

デフォルトアクションは、ビジュアル要素のサブクラスのインスタンスがイベントを受け取ったときに、各インスタンス上で実行されます。デフォルトアクションをカスタマイズするには、以下の例のように、 ExecuteDefaultActionAtTarget()ExecuteDefaultAction() をオーバーライドします。

override void ExecuteDefaultActionAtTarget(EventBase evt)
{
    // 基礎関数を呼び出す
    base.ExecuteDefaultActionAtTarget(evt);

    if (evt.GetEventTypeId() == MouseDownEvent.TypeId())
    {
        // ...
    }
    else if (evt.GetEventTypeId() == MouseUpEvent.TypeId())
    {
        // ...
    }
    // イベントタイプを追加
}

ExecuteDefaultAction() にデフォルトアクションを実装すると、デフォルトのアクションの実行を停止または防止できます。

ターゲットのデフォルトアクションを親のコールバックの前に実行したい場合は、デフォルトアクションを ExecuteDefaultActionAtTarget() に実装します。

デフォルトアクションは、あるタイプの要素がイベントを受け取ったときの動作と考える必要があります。例えば、チェックボックスは、クリックイベントに反応して、その状態を切り替えます。これを実行するには、すべてのチェックボックスにコールバックを登録するのではなく、デフォルトアクションの仮想関数をオーバーライドします。

カスタム制御の実践例

以下は、カスタムコントロールの効率的な実践例です。

動作の実装

要素の動作をデフォルトの動作で実装する必要があります。インスタンスに接続されたコールバックで PreventDefault() を呼び出すことで、要素のデフォルトの動作をキャンセルすることができます。

動作をデフォルトアクションとして実装することによるその他の利点は以下の通りです。

  • デフォルトアクションが、コールバックレジストリのルックアップを必要としません。
  • コールバックのないインスタンスは伝搬プロセスに入りません。

柔軟性を高めるために、イベントのディスパッチ処理中にイベントターゲットのデフォルトのアクションを 2 か所で実行できます。

  1. 下降と上昇の伝播段階の間で、ターゲットコールバックの実行直後に、ExecuteDefaultActionsAtTarget() をオーバーライドします。
  2. イベントのディスパッチプロセスの最後に、ExecuteDefaultActions() をオーバーライドします。

クラスのデフォルトアクション

可能であれば ExecuteDefaultActions() にクラスのデフォルトアクションを実装してください。これにより、クラスをオーバーライドするためのオプションが増えます。PreventDefault() を呼び出して、イベント伝播プロセスの降下段階または上昇段階でクラスをオーバーライドすることができます。

イベントが親要素に伝搬してはいけない場合は、デフォルトアクション中にイベントの伝搬を停止する必要があります。例えば、テキストフィールドは KeyDownEvent を受け取って、その値を変更します。例えば、Delete キーでコンテンツを削除するように。このイベントは、親のビジュアル要素に伝播してはいけません。ExecuteDefaultActionsAtTarget() を使ってデフォルトアクションを実装し、StopPropagation() を呼び出して上昇段階でイベントが処理されないようにします。

デフォルトアクションは、イベントターゲットに対してのみ実行されます。クラスが子要素や親要素を対象としたイベントに反応するには、降下または上昇の伝搬段階で、イベントを受け取るコールバックを登録する必要があります。パフォーマンスを向上させるために、クラスにコールバックを登録することは避けてください。

イベント伝播の停止とデフォルトアクションのキャンセル

コールバックやデフォルトアクションの中でイベントを処理する場合、イベントの伝搬やデフォルトアクションの実行を停止することができます。例えば、親パネルは降下段階で伝搬を停止し、子パネルがイベントを受け取らないようにすることができます。

EventBase.PreDispatch()EventBase.PostDispatch() メソッドの実行は、イベントクラスの内部で防ぐことはできません。

以下のメソッドは、イベント伝播とデフォルトアクションに影響します。

  • StopImmediatePropagation(): Stops the event propagation process immediately, so no other callbacks execute for the event. However, the ExecuteDefaultActionAtTarget() and ExecuteDefaultAction() default actions still execute.
  • StopPropagation(): Stops the event propagation process after the last callback on the current element. This ensures that all callbacks execute on the current element, but no further elements react to the event. The ExecuteDefaultActionAtTarget() and ExecuteDefaultAction() default actions still execute.
  • PreventDefaultAction(): Prevents the event propagation process from calling the ExecuteDefaultActionAtTarget() and ExecuteDefaultAction() default actions. PreventDefaultAction() doesn’t prevent the execution of other callbacks and doesn’t effective the ExecuteDefaultActionAtTarget() action during the bubble-up phase.
Dispatching events
Synthesizing events