Version: 2019.2
イベントシステム
イベントへの応答

イベントのディスパッチ

UIElements は、オペレーティングシステムやスクリプトからのイベントをリッスンし、EventDispatcher でこれらのイベントをディスパッチします。イベントディスパッチャーは、イベントを送信するためのディスパッチ方法を決定し、方法を決定したらそれを実行します。

ビジュアル要素やその他のサポートするクラスは、いくつかのイベントに対してデフォルトの動作を実装します。追加のイベントを作成して送信する場合もあります。例えば、MouseMoveEvent は追加の MouseEnterEvent と MouseLeaveEvent を作成できます。これらの追加イベントはキューに置かれ、現在のイベントが完了した後に処理されます。例えば、MouseMoveEvent は MouseEnterEvent と MouseLeaveEvent イベントを処理する前に完了します。

イベントターゲット

EventDispatcher.DispatchEvent() の最初のタスクは、イベントのターゲットを見つけることです。

イベントの target プロパティーが既に設定されているため、これは簡単なことです。ただし、オペレーティングシステムから発生するほとんどのイベントの場合は、簡単ではありません。

イベントのターゲットは、イベントの種類によって異なります。マウスイベントの場合、ターゲットは通常、直接マウスの下にある最も選択される可能性の高い要素です。キーボードイベントの場合、ターゲットは現在フォーカスされている要素です。

ターゲットが見つかると EventBase.target に格納され、ディスパッチ処理の間は変更されません。Event.currentTarget プロパティーは、現在イベントを処理している要素に更新されます。

選択モードとカスタムシェイプ

ほとんどのマウスイベントは、選択 (picking) モードを使用してターゲットを決定します。VisualElement クラスは以下の値をサポートする pickingMode プロパティーを持っています。

  • PickingMode.Position(デフォルト): 位置の矩形に基づいて選択します。
  • PickingMode.Ignore: マウスイベントの結果によって選択することを防ぎます。

VisualElement.ContainsPoint() メソッドをオーバーライドすると、カスタムの交差ロジックを行えます。

マウスのキャプチャ

マウスダウンされた後、ポインターがその要素上にもうマウスオーバーしていない場合でも、要素がマウスの位置を取得し、後続のすべてのマウスイベントを排他的に受信できるようにする必要があります。これは、マウスダウンとマウスアップのイベントの間にマウスが移動する動きに対応する制御には典型的です。ボタン、スライダー、スクロールバーなどのクリックなどが、その例です。

マウスをキャプチャするには、element.CaptureMouse() か MouseCaptureController.CaptureMouse() を呼び出します。

マウスをリリースするには MouseCaptureController.ReleaseMouse() を呼び出します。CaptureMouse() の呼び出し時に他の要素がすでにマウスをキャプチャしている場合、その要素は MouseCaptureOutEvent を受け取り、キャプチャしなくなります。

どのような時でも、アプリケーションの 1 つの要素だけがキャプチャできます。要素はキャプチャできますが、マウスホイールイベントを除くすべての後続のマウスイベントのターゲットにもなります。

注意: これは、まだターゲットが設定されていないマウスイベントにのみ当てはまります。

フォーカスリングとフォーカスの順序

各 UIElement パネルには、要素のフォーカスの順序を定義するフォーカスリングがあります。デフォルトでは、要素のフォーカス順序は、ビジュアル要素ツリーで深さ優先探索 (DFS) を実行することによって決まります。例えば、下に描かれているツリーのフォーカス順序は、F、B、A、D、C、E、G、I、H です。

フォーカスの順序
フォーカスの順序

イベントによっては、どの要素にフォーカスがあるかを決定するためにフォーカス順序を使用するものがあります。例えば、キーボードイベントのターゲットは、現在フォーカスを保持している要素です。

  • 要素のフォーカスする動作を制御するには、focusable プロパティーを使用します。デフォルトで VisualElements はフォーカス可能ではありませんが、TextField などのサブクラスの中には、デフォルトでフォーカス可能なものがあります。

フォーカスの順序を制御するには、tabIndex プロパティーを使用します (tabIndex のデフォルト値は 0。

  • tabIndex が負の場合、その要素はタブ化できません。
  • focus-index が 0 の場合、要素はフォーカスリングアルゴリズムによって決定されたデフォルトのフォーカス順序を維持します。
  • tabIndex が正の場合、その要素は tabIndexが 0 以上の他の要素の前に置かれます。

イベント伝播

イベントターゲットを選択すると、ディスパッチャーはイベントの伝搬経路を計算します。伝播経路は、イベントを受け取るビジュアル要素が順序通りに並べられたリストです。

要素のリストは、ビジュアル要素のツリーのルートから開始し、ターゲットに向かって降りながら取得されます。ターゲットに達した後、ルートに向かって昇りながら取得されます。

伝播経路
伝播経路

伝播経路の最初の段階はルートからターゲットの親に下降します。これを 下降段階 (TrickleDown) と呼びます。

伝播経路の最後の段階は、ターゲットの親からルートに向かって上昇します。これを 上昇段階 (BubbleUp) と呼びます。

イベントターゲットは伝搬経路の途中にあります。

ほとんどのイベントタイプは、伝播経路に沿ったすべての要素に送信されます。ただし、上昇段階をスキップするイベントもあります。さらに、一部のイベントタイプはイベントターゲットにのみ送信されます。

要素が非表示または無効の場合、イベントを受信しません。イベントは非表示の要素や無効な要素の祖先や子孫にも伝播されます。

イベントが伝播経路に沿って送信されるとき、Event.currentTarget は現在イベントを処理している要素に更新されます。これは、イベントコールバック関数内で、Event.currentTarget はコールバックが登録された要素であり、Event.target はイベントが発生した要素であることを意味します。

イベントタイプのディスパッチ動作

各イベントタイプには独自のディスパッチ動作があります。以下の表は、各イベントタイプの挙動をまとめたものです。

  • 下降: このタイプのイベントは、下降段階中に要素に送信されます。
  • 上昇: このタイプのイベントは、上昇段階中に要素に送信されます。
  • キャンセル可能: このタイプのイベントは、デフォルトのアクションの実行をキャンセル、停止、防止することができます。
下降 上昇 キャンセル可能
MouseCaptureOutEvent ✔ ✔
MouseCaptureEvent ✔ ✔
ChangeEvent ✔ ✔
ValidateCommandEvent ✔ ✔ ✔
ExecuteCommandEvent ✔ ✔ ✔
DragExitedEvent ✔ ✔
DragUpdatedEvent ✔ ✔ ✔
DragPerformEvent ✔ ✔ ✔
DragEnterEvent ✔
DragLeaveEvent ✔
FocusOutEvent ✔ ✔
BlurEvent ✔
FocusInEvent ✔ ✔
FocusEvent ✔
InputEvent ✔ ✔
KeyDownEvent ✔ ✔ ✔
KeyUpEvent ✔ ✔ ✔
GeometryChangedEvent
MouseDownEvent ✔ ✔ ✔
MouseUpEvent ✔ ✔ ✔
MouseMoveEvent ✔ ✔ ✔
ContextClickEvent ✔ ✔ ✔
WheelEvent ✔ ✔ ✔
MouseEnterEvent ✔ ✔
MouseLeaveEvent ✔ ✔
MouseEnterWindowEvent ✔
MouseLeaveWindowEvent ✔
MouseOverEvent ✔ ✔ ✔
MouseOutEvent ✔ ✔ ✔
ContextualMenuPopulateEvent ✔ ✔ ✔
AttachToPanelEvent
DetachFromPanelEvent
TooltipEvent ✔ ✔
IMGUIEvent ✔ ✔ ✔

  • 2018–11–02 Page amended
イベントシステム
イベントへの応答