3 イベント・フィルタの使用
このトピックでは、JavaFXアプリケーションにおけるイベント・フィルタについて説明します。キーボード・アクション、マウス・アクション、スクロール・アクションなど、ユーザーがアプリケーションと対話するときに生成されるイベントをイベント・フィルタによって処理する方法を取り上げます。
イベント・フィルタを使用すると、イベント処理のイベント・キャプチャ・フェーズでイベントを処理できます。ノードには、イベントを処理するためのフィルタを1つ以上登録できます。1つのフィルタを複数のノードおよび複数のイベント・タイプに使用できます。イベント・フィルタは、親ノードで子ノードの処理を共通化したり、イベントをインターセプトしてそのイベントに対して子ノードが作用しないようにする目的で使用します。
イベント・フィルタの登録および削除
イベント・キャプチャ・フェーズでイベントを処理するには、ノードにイベント・フィルタを登録する必要があります。イベント・フィルタは、EventHandler
インタフェースの実装です。フィルタが登録されているノードにそのフィルタに関連付けられているイベントが渡された場合に、このインタフェースのhandle()
メソッドを通してコードが実行されます。
フィルタを登録するには、addEventFilter()
メソッドを使用します。このメソッドには、引数としてイベント・タイプとフィルタを渡します。例3-1では、1つ目のフィルタを単一のノードに追加し、そのフィルタにより特定のイベント・タイプを処理するように指定しています。入力イベントを処理するための2つ目のフィルタを2つの異なるノードに定義および登録しています。また、同じフィルタを2つの異なるイベント・タイプ用に登録しています。
例3-1 フィルタの登録
// Register an event filter for a single node and a specific event type node.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() { public void handle(MouseEvent) { ... }; }); // Define an event filter EventHandler filter = new EventHandler(<InputEvent>() { public void handle(InputEvent event) { System.out.println("Filtering out event " + event.getEventType()); event.consume(); } // Register the same filter for two different nodes myNode1.addEventFilter(MouseEvent.MOUSE_PRESSED, filter); myNode2.addEventFilter(MouseEvent.MOUSE_PRESSED, filter); // Register the filter for another event type myNode1.addEventFilter(KeyEvent.KEY_PRESSED, filter);
1つのイベント・タイプ用として定義したイベント・フィルタは、そのイベントのサブタイプにも使用できます。イベント・タイプの階層の詳細は、「イベント・タイプ」を参照してください。
イベント・フィルタによるイベントの処理が特定のノードまたはイベント・タイプに対して不要になった場合は、removeEventFilter()
メソッドを使用してフィルタを削除します。このメソッドには、引数としてイベント・タイプとフィルタを渡します。例3-2では、例3-1で定義したフィルタをmyNode1
のMouseEvent.MOUSE_PRESSED
イベントに対して削除しています。KeyEvent.KEY_PRESSED
イベントに対しては、myNode2
およびmyNode1
で引き続きフィルタが実行されます。
イベント・フィルタの使用
イベント・フィルタは、一般にイベント・ディスパッチ・チェーンのブランチ・ノードで使用し、イベント処理のイベント・キャプチャ・フェーズでコールします。イベント・レスポンスをオーバーライドしたり、イベントが宛先に送信されるのをブロックする場合などに、フィルタを使用します。
フィルタの使用方法を示す例を参照するには、DraggablePanelsExample.zip
ファイルをダウンロードします。NetBeansプロジェクトを抽出し、NetBeans IDEで開きます。次の項では、この例で使用されているフィルタについて説明します。
ドラッグ可能パネルの例
ドラッグ可能パネルの例では、次のフィルタの使用方法を例示しています。
-
スーパータイプ・イベント用のフィルタを登録し、サブタイプ・イベントの処理を共通化します。
-
イベントを消費してそのイベントに対して子ノードが作用しないようにします。
図3-1に、ドラッグ可能パネルの例を開始したときに表示される画面を示します。ユーザー・インタフェースは3つのパネルで構成されます。各パネルのUIコントロールはそれぞれ異なります。画面下部には、パネルのドラッグを許可するかどうかを制御するチェック・ボックスがあります。
チェック・ボックスの選択を解除した場合、パネル内のいずれかのコントロールをクリックすると、そのコントロールからレスポンスが生成されます。チェック・ボックスを選択した場合、マウス・クリックに対する各コントロールのレスポンスはありません。かわりに、パネル内の任意の場所をクリックしてマウスをドラッグすると、パネル全体が動き、図3-2に示すようにパネルの位置を変更できます。
ドラッグ可能パネルの例のフィルタ
ドラッグ可能パネルの例では、3つのパネルの作成時にmakeDraggable()
メソッドを使用して各パネルを移動可能にしています。例3-3に、このメソッドとフィルタ定義を示します。
例3-3 makeDraggable()におけるフィルタ定義
private Node makeDraggable(final Node node) { final DragContext dragContext = new DragContext(); final Group wrapGroup = new Group(node); wrapGroup.addEventFilter( MouseEvent.ANY, new EventHandler<MouseEvent>() { public void handle(final MouseEvent mouseEvent) { if (dragModeActiveProperty.get()) { // disable mouse events for all children mouseEvent.consume(); } } }); wrapGroup.addEventFilter( MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() { public void handle(final MouseEvent mouseEvent) { if (dragModeActiveProperty.get()) { // remember initial mouse cursor coordinates // and node position dragContext.mouseAnchorX = mouseEvent.getX(); dragContext.mouseAnchorY = mouseEvent.getY(); dragContext.initialTranslateX = node.getTranslateX(); dragContext.initialTranslateY = node.getTranslateY(); } } }); wrapGroup.addEventFilter( MouseEvent.MOUSE_DRAGGED, new EventHandler<MouseEvent>() { public void handle(final MouseEvent mouseEvent) { if (dragModeActiveProperty.get()) { // shift node from its initial position by delta // calculated from mouse cursor movement node.setTranslateX( dragContext.initialTranslateX + mouseEvent.getX() - dragContext.mouseAnchorX); node.setTranslateY( dragContext.initialTranslateY + mouseEvent.getY() - dragContext.mouseAnchorY); } } }); return wrapGroup; }
各パネルに対して次のイベントのフィルタを定義および登録しています。
-
MouseEvent.ANY
。このフィルタでは、パネルに対するすべてのマウス・イベントを処理します。ドラッグ・モード・チェック・ボックスを選択した場合、フィルタによりイベントが消費され、子ノード(パネル内のUIコントロール)にイベントが渡されなくなります。チェック・ボックスの選択を解除した場合、マウス・カーソルの位置にあるコントロールによってイベントが処理されます。 -
MouseEvent.MOUSE_PRESSED
。このフィルタでは、パネルに対するマウス押下イベントのみを処理します。ドラッグ・モード・チェック・ボックスを選択した場合、マウスの現在の位置が保存されます。 -
MouseEvent.MOUSE_DRAGGED
。このフィルタでは、パネルに対するマウス・ドラッグ・イベントのみを処理します。ドラッグ・モード・チェック・ボックスを選択した場合、パネルが移動されます。
パネルには3つのフィルタが登録されています。スーパータイプ・イベントよりも先に特定のイベント・タイプ用のフィルタが呼び出されるため、MouseEvent.MOUSE_PRESSED
およびMouseEvent.MOUSE_DRAGGED
のフィルタはMouseEvent.ANY
のフィルタよりも先に呼び出されます。