Version: 2022.2
言語: 日本語
Dispatch events
イベントの統合と送信

Handle events

Events in UI Toolkit are similar to HTML events. When an event occurs, it’s sent to the target visual element and to all elements within the propagation path in the visual element tree.

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

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

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

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

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

Register an event callback

You can register an event callback to customize the behavior of an individual instance of an existing class, such as reacting to a mouse click on a text label.

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

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

By default, a registered callback executes during the target phase and the bubble-up phase. This default behavior ensures that a parent element reacts after its child element.

On the other hand, if you want a parent element to react before its child, register your callback with the TrickleDown.TrickleDown option:

using UnityEngine;
using UnityEngine.UIElements;

...
VisualElement myElement = new VisualElement();

// Register a callback for the trickle-down phase.
myElement.RegisterCallback<MouseDownEvent>(MyCallback, TrickleDown.TrickleDown);
...

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

To add a custom behavior to a specific visual element, register an event callback on that element.

The following example registers a callback for the MouseDownEvent:

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

The signature for the callback function looks like this:

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

You can register multiple callbacks for an event. However, you can only register the same callback function on the same event and propagation phase once.

To remove a callback from a VisualElement, call the myElement.UnregisterCallback() method.

Send custom data to an event callback

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

The following example registers a callback for the MouseDownEvent and sends custom data to the callback function:

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

The signature for the callback function looks like this:

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

Listen to value changes

UI controls can use the value property to hold data for their internal state. For example:

  • A Toggle holds a Boolean value that changes when the Toggle is turned on or off.
  • An IntegerField holds an integer that holds the field’s value.

You can get the value of the control by the following:

  • Get the value from the control directly: int val = myIntegerField.value;.

  • Listen to a ChangeEvent sent by the control and process the change when it happens. You must register your callback to the event like this:

    //RegisterValueChangedCallback is a shortcut for RegisterCallback<ChangeEvent>. 
    //It constrains the right type of T for any VisualElement that implements an 
    //INotifyValueChange interface.
    myIntegerField.RegisterValueChangedCallback(OnIntegerFieldChange); 
    

    The signature for the callback function looks like this:

    void OnIntegerFieldChange(ChangeEvent<int> evt) { /* ... */ }
    

You can change the value of a control by the following:

  • Directly change the value variable: myControl.value = myNewValue;. This will trigger a new ChangeEvent.
  • Use myControl.SetValueWithoutNotify(myNewValue);. This won’t trigger a new ChangeEvent.

For more information, see Change events

Handle input events for a control

You can use an event handler or use a manipulator to handle input events.

Capture the pointer

When you handle pointer input, you might want the control to capture a pointer. When a visual element captures a pointer, Unity sends all the events associated with the pointer to the visual element regardless of whether the pointer hovers over the visual element. For example, if you create a control that receives drag events and captures the pointer, the control still receives drag events regardless of the pointer location.

To capture a pointer, use capture events. See Create a drag-and-drop UI inside a custom Editor window for an example.

Use a manipulator to handle events

If you want to separate your event logic from your UI code, use a manipulator to handle events. A manipulator is a dedicated class that stores, registers, and unregisters event callbacks. You can use or inherit from one of the manipulators that UI Toolkit supports to handle events.

UI Toolkit supports the following manipulators:

Manipulator Inherits from 説明 
Manipulator Base class for all provided manipulators.
KeyboardNavigationManipulator Manipulator Handles translation of device-specific input events to higher-level navigation operations with a keyboard.
MouseManipulator Manipulator Handles mouse input. Has a list of activation filters.
ContextualMenuManipulator MouseManipulator Displays a contextual menu when the user clicks the right mouse button or presses the menu key on the keyboard.
PointerManipulator MouseManipulator Handles pointer input. Has a list of activation filters.
Clickable PointerManipulator Tracks mouse events on an element and callbacks when a user clicks a mouse button while the pointer hovers over an element.

Respond to events with custom controls

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

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

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

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

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

Implement a default action

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

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

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

override void ExecuteDefaultActionAtTarget(EventBase evt)
{
    // Call the base function.
    base.ExecuteDefaultActionAtTarget(evt);

    if (evt.eventTypeId == MouseDownEvent.TypeId())
    {
        // ...
    }
    else if (evt.eventTypeId == MouseUpEvent.TypeId())
    {
        // ...
    }
    // More event types
}

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

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

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

カスタム制御の実践例

The following are best practices for custom controls.

Implement behaviors

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

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

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

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

  • Between the trickle-down and the bubble-up propagation phase, immediately after execution of the target callbacks, override ExecuteDefaultActionsAtTarget().
  • At the end of the event dispatch process, override ExecuteDefaultActions().

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

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

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

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

Stop event propagation and cancel default actions

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

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 affect the ExecuteDefaultActionAtTarget() action during the bubble-up phase.

その他の参考資料

Dispatch events
イベントの統合と送信