5 タッチ対応デバイスからのイベントの使用
このトピックでは、タッチ・イベント、ズーム・イベント、回転イベント、スワイプ・イベントなど、タッチ対応デバイスによって認識される各種ジェスチャによって生成されるイベントについて説明します。 このトピックでは、JavaFXアプリケーションでこのようなタイプのイベントを扱う方法を紹介します。
JavaFX 2.2以降、ユーザーは、タッチ対応デバイスでタッチやジェスチャを行うことによってJavaFXアプリケーションと対話できるようになりました。 タッチおよびジェスチャには、単一または複数の接触ポイントが関与する場合があります。 生成されるイベントのタイプは、ユーザーが実行したタッチまたはジェスチャのタイプによって決まります。
タッチ・イベントおよびジェスチャ・イベントの処理方法は、その他のイベントの場合と同じです。 この処理の詳細は、「イベントの処理」を参照してください。 タッチ・イベントおよびジェスチャ・イベントのイベント・ハンドラを登録するためのコンビニエンス・メソッドが用意されています。 詳細は、「コンビニエンス・メソッドの使用」を参照してください。
ジェスチャ・イベントおよびタッチ・イベント
ジェスチャを認識するタッチ画面またはトラックパッド付きのデバイスでJavaFXアプリケーションを実行している場合は、アプリケーションによってジェスチャ・イベントが生成されます。 ジェスチャを認識するプラットフォームの場合、実行されたジェスチャはネイティブ認識によって識別されます。 表5-1に、サポートされているジェスチャとそれに対応して生成されるイベント・タイプを示します。
表5-1 サポートされているジェスチャと生成されるイベント・タイプ
| ジェスチャ | 説明 | 生成されるイベント |
|---|---|---|
|
回転 |
2本の指で回転させる動作です。1本の指を中心にもう1本の指を時計回りに動かすと、オブジェクトが時計回りに回転し、1本の指を中心にもう1本の指を反時計回りに動かすと、オブジェクトが反時計回りに回転します。 |
|
|
スクロール |
上下(垂直スクロールの場合)または左右(水平スクロールの場合)にスライドさせる動作です。 |
マウス・ホイールを使用してスクロールする場合は、 |
|
スワイプ |
画面またはトラックパッド上で指を上下左右に滑らせる動作です。 斜め方向の動作はスワイプと認識されません。 |
1回のスワイプ・ジェスチャにつき1つのスワイプ・イベントが生成されます。 |
|
ズーム |
2本の指でつまむ動作です。2本の指を近づけるとズーム・アウトし、2本の指を遠ざけるとズーム・インします。 |
|
タッチ画面付きのデバイスでアプリケーションを実行している場合に、ユーザーが1本以上の指で画面にタッチすると、タッチ・イベントが生成されます。 これらのイベントを使用すると、タッチまたはジェスチャを構成する個々のタッチ・ポイントを掘り下げて追跡できます。 タッチ・イベントの詳細は、「タッチ・イベントの使用」を参照してください。
ジェスチャのターゲット
ほとんどのジェスチャのターゲットは、ジェスチャ開始時のすべてのタッチの中心にあるノードです。 スワイプ・ジェスチャのターゲットは、すべての指の経路全体の中心にあるノードです。
ターゲット・ポイントに複数のノードが存在する場合は、最上位ノードがターゲットとみなされます。 ジェスチャの慣性を含め、単一の連続ジェスチャから複数のイベントが生成される場合は、ジェスチャ開始時に選択されたノードにすべてのイベントが送信されます。 イベントのターゲットの詳細は、「ターゲットの選択」を参照してください。
生成されるその他のイベント
ジェスチャおよびタッチが実行されたときには、対応するジェスチャ・イベントまたはタッチ・イベントだけでなく、その他のタイプのイベントも生成できます。 スワイプ・ジェスチャでは、スワイプ・イベントだけでなく、スクロール・イベントも生成されます。 スワイプの長さに応じて、スワイプ・イベントとスクロール・イベントのターゲットが異なる場合があります。 スクロール・イベントのターゲットは、ジェスチャが開始されたポイントにあるノードです。 スワイプ・イベントのターゲットは、ジェスチャの経路全体の中心にあるノードです。
タッチ画面へのタッチでは、対応するマウス・イベントも生成されます。 たとえば、画面上のポイントにタッチすると、TOUCH_PRESSEDイベントとMOUSE_PRESSEDイベントが生成されます。 画面上の単一ポイントを移動すると、スクロール・イベントとドラッグ・イベントが生成されます。 タッチ・イベントまたはジェスチャ・イベントをアプリケーションで直接処理できない場合でも、タッチの実行時に生成されるマウス・イベントに対するレスポンスを生成するように変更するだけで、タッチ対応デバイスでアプリケーションを実行できるようになります。
アプリケーションでタッチ、ジェスチャおよびマウス・イベントが処理される場合は、1つのアクションを複数回処理しないように注意してください。 たとえば、ジェスチャの実行時にスクロール・イベントとドラッグ・イベントが生成される場合に、両方のタイプのイベントのハンドラで同じ処理を適用すると、画面上での動作が想定量の2倍になります。 マウス・イベントに対してisSynthesized()メソッドを使用すると、イベントがマウスの動作によって生成されたのか、それともタッチ画面上の動作によって生成されたのかを判別し、イベント処理の重複を回避できます。
ジェスチャ・イベントの例
ジェスチャ・イベントの例は、四角形、楕円およびイベント・ログを示しています。 図5-1に、この例を示します。
ログには、処理されたイベントが記録されています。 この例では、様々なジェスチャを試し、各ジェスチャにより生成されるイベントを確認できます。
ジェスチャ・イベントの例は、GestureEventsExample.zipファイルで提供されています。 NetBeansプロジェクトを抽出し、NetBeans IDEで開きます。
ジェスチャ・イベントを生成するには、ジェスチャに対応したタッチ画面またはトラックパッド付きのデバイスで例を実行する必要があります。 タッチ・イベントを生成するには、タッチ画面付きのデバイスで例を実行する必要があります。
図形の作成
ジェスチャ・イベントの例は、四角形および楕円を示しています。 例5-1に、各図形とそれらを配置するレイアウト・ペインを作成するためのコードを示します。
例5-1 図形の設定
// Create the shapes that respond to gestures and use a VBox to
// organize them
VBox shapes = new VBox();
shapes.setAlignment(Pos.CENTER);
shapes.setPadding(new Insets(15.0));
shapes.setSpacing(30.0);
shapes.setPrefWidth(500);
shapes.getChildren().addAll(createRectangle(), createEllipse());
...
private Rectangle createRectangle() {
final Rectangle rect = new Rectangle(100, 100, 100, 100);
rect.setFill(Color.DARKMAGENTA);
...
return rect;
}
private Ellipse createEllipse() {
final Ellipse oval = new Ellipse(100, 50);
oval.setFill(Color.STEELBLUE);
...
return oval;
}
ジェスチャを使用して、これらのオブジェクトの移動、回転およびズーム・イン/ズーム・アウトを行うことができます。
イベントの処理
一般に、ジェスチャ・イベントの例で使用されている図形オブジェクトのイベント・ハンドラでは、処理されるイベントのタイプごとに同じような操作が実行されます。 あらゆるタイプのイベントのエントリがイベント・ログに掲載されます。
ジェスチャの慣性をサポートしているプラットフォームでは、event-type_FINISHEDイベントの後に追加のイベントが生成されることがあります。 たとえば、スクロール・ジェスチャになんらかの慣性が関連付けられている場合は、SCROLL_FINISHEDイベントの後にSCROLLイベントが生成されることがあります。 ジェスチャの慣性に基づいて生成されるイベントを識別するには、isInertia()メソッドを使用します。 このメソッドによってtrueが返された場合は、ジェスチャの完了後にイベントが生成されています。
イベントはタッチ画面またはトラックパッド上でのジェスチャによって生成されます。 SCROLLイベントはマウス・ホイールによっても生成されます。 イベントのソースを識別するには、isDirect()メソッドを使用します。 このメソッドによってtrueが返された場合は、タッチ画面上でのジェスチャによってイベントが生成されています。 それ以外の場合、このメソッドはfalseを返します。 この情報を使用すると、イベントのソースに基づいて様々な動作を提供できます。
タッチ画面へのタッチでは、対応するマウス・イベントも生成されます。 たとえば、オブジェクトにタッチすると、TOUCH_PRESSEDイベントとMOUSE_PRESSEDイベントの両方が生成されます。 マウス・イベントのソースを識別するには、isSynthesized()メソッドを使用します。 このメソッドによってtrueが返された場合は、マウスではなくタッチによってイベントが生成されています。
ジェスチャ・イベントの例では、inc()メソッドおよびdec()メソッドを使用して、オブジェクトがジェスチャのターゲットであることを視覚的に判断できるようにしています。 進行中のジェスチャの数が追跡され、アクティブなジェスチャの数が0から1に変わるか、0になると、ターゲット・オブジェクトの外観が変わります。
ジェスチャ・イベントの例では、四角形と楕円のハンドラは似ています。 したがって、次の項では、四角形のハンドラのコード例を紹介します。 楕円のハンドラは、「GestureEvents.java」を参照してください。
スクロール・イベントの処理
スクロール・ジェスチャが実行されると、SCROLL_STARTED、SCROLLおよびSCROLL_FINISHEDイベントが生成されます。 マウス・ホイールの移動では、SCROLLイベントのみが生成されます。 例5-2に、ジェスチャ・イベントの例におけるスクロール・イベントに対する四角形のハンドラを示します。 楕円のハンドラも同じようなものです。
例5-2 スクロール・イベントのハンドラの定義
rect.setOnScroll(new EventHandler<ScrollEvent>() {
@Override public void handle(ScrollEvent event) {
if (!event.isInertia()) {
rect.setTranslateX(rect.getTranslateX() + event.getDeltaX());
rect.setTranslateY(rect.getTranslateY() + event.getDeltaY());
}
log("Rectangle: Scroll event" +
", inertia: " + event.isInertia() +
", direct: " + event.isDirect());
event.consume();
}
});
rect.setOnScrollStarted(new EventHandler<ScrollEvent>() {
@Override public void handle(ScrollEvent event) {
inc(rect);
log("Rectangle: Scroll started event");
event.consume();
}
});
rect.setOnScrollFinished(new EventHandler<ScrollEvent>() {
@Override public void handle(ScrollEvent event) {
dec(rect);
log("Rectangle: Scroll finished event");
event.consume();
}
});
イベントの処理で説明した共通の処理に加え、SCROLLイベントの処理として、スクロール・ジェスチャの方向にオブジェクトが移動されます。 スクロール・ジェスチャがウィンドウの外部で終了した場合、図形はウィンドウの外部に移動されます。 四角形のハンドラでは、慣性に基づいて生成されるSCROLLイベントは無視されます。 楕円のハンドラでは、慣性に基づいて生成されるSCROLLイベントに応じて楕円の移動が継続され、ジェスチャがウィンドウの内部で終了した場合でも、楕円はウィンドウの外部に移動される可能性があります。
ズーム・イベントの処理
ズーム・ジェスチャが実行されると、ZOOM_STARTED、ZOOMおよびZOOM_FINISHEDイベントが生成されます。 例5-3に、ジェスチャ・イベントの例におけるズーム・イベントに対する四角形のハンドラを示します。 楕円のハンドラも同じようなものです。
例5-3 ズーム・イベントのハンドラの定義
rect.setOnZoom(new EventHandler<ZoomEvent>() {
@Override public void handle(ZoomEvent event) {
rect.setScaleX(rect.getScaleX() * event.getZoomFactor());
rect.setScaleY(rect.getScaleY() * event.getZoomFactor());
log("Rectangle: Zoom event" +
", inertia: " + event.isInertia() +
", direct: " + event.isDirect());
event.consume();
}
});
rect.setOnZoomStarted(new EventHandler<ZoomEvent>() {
@Override public void handle(ZoomEvent event) {
inc(rect);
log("Rectangle: Zoom event started");
event.consume();
}
});
rect.setOnZoomFinished(new EventHandler<ZoomEvent>() {
@Override public void handle(ZoomEvent event) {
dec(rect);
log("Rectangle: Zoom event finished");
event.consume();
}
});
イベントの処理で説明した共通の処理に加え、ZOOMイベントの処理として、ジェスチャの動作に応じてオブジェクトが拡大/縮小されます。 四角形と楕円のハンドラでは、慣性やイベントのソースに関係なく、すべてのZOOMイベントが同じ方法で処理されます。
回転イベントの処理
回転ジェスチャが実行されると、ROTATE_STARTED、ROTATEおよびROTATE_FINISHEDイベントが生成されます。 例5-4に、ジェスチャ・イベントの例における回転イベントに対する四角形のハンドラを示します。 楕円のハンドラも同じようなものです。
例5-4 回転イベントのハンドラの定義
rect.setOnRotate(new EventHandler<RotateEvent>() {
@Override public void handle(RotateEvent event) {
rect.setRotate(rect.getRotate() + event.getAngle());
log("Rectangle: Rotate event" +
", inertia: " + event.isInertia() +
", direct: " + event.isDirect());
event.consume();
}
});
rect.setOnRotationStarted(new EventHandler<RotateEvent>() {
@Override public void handle(RotateEvent event) {
inc(rect);
log("Rectangle: Rotate event started");
event.consume();
}
});
rect.setOnRotationFinished(new EventHandler<RotateEvent>() {
@Override public void handle(RotateEvent event) {
dec(rect);
log("Rectangle: Rotate event finished");
event.consume();
}
});
イベントの処理で説明した共通の処理に加え、ROTATEイベントの処理として、ジェスチャの動作に応じてオブジェクトが回転されます。 四角形と楕円のハンドラでは、慣性やイベントのソースに関係なく、すべてのROTATEイベントが同じ方法で処理されます。
スワイプ・イベントの処理
スワイプ・ジェスチャが実行されると、スワイプの方向に応じて、SWIPE_DOWN、SWIPE_LEFT、SWIPE_RIGHTまたはSWIPE_UPイベントのいずれかが生成されます。 例5-5に、ジェスチャ・イベントの例におけるSWIPE_RIGHTイベントおよびSWIPE_LEFTイベントに対する四角形のハンドラを示します。 楕円の場合、スワイプ・イベントは処理されません。
例5-5 スワイプ・イベントのハンドラの定義
rect.setOnSwipeRight(new EventHandler<SwipeEvent>() {
@Override public void handle(SwipeEvent event) {
log("Rectangle: Swipe right event");
event.consume();
}
});
rect.setOnSwipeLeft(new EventHandler<SwipeEvent>() {
@Override public void handle(SwipeEvent event) {
log("Rectangle: Swipe left event");
event.consume();
}
});
スワイプ・イベントに応じて実行されるアクションは、ログへのイベントの記録のみです。 ただし、スワイプ・ジェスチャではスクロール・イベントも生成されます。 スワイプ・イベントのターゲットは、ジェスチャの経路の中心にある最上位ノードです。 このターゲットは、スクロール・イベントのターゲット(ジェスチャが開始されたポイントにある最上位ノード)とは異なる場合があります。 四角形と楕円がスクロール・イベントのターゲットになっている場合、スワイプ・ジェスチャによって生成されるスクロール・イベントに対してレスポンスが返されます。
タッチ・イベントの処理
タッチ画面へのタッチが発生すると、各タッチ・ポイントでTOUCH_MOVED、TOUCH_PRESSED、TOUCH_RELEASEDまたはTOUCH_STATIONARYイベントが生成されます。 タッチ・イベントでは、タッチ・アクションを構成するすべてのタッチ・ポイントの情報が扱われます。 例5-6に、ジェスチャ・イベントの例におけるタッチ押下イベントおよびタッチ解放イベントに対する四角形のハンドラを示します。 楕円の場合、タッチ・イベントは処理されません。
例5-6 タッチ・イベントのハンドラの定義
rect.setOnTouchPressed(new EventHandler<TouchEvent>() {
@Override public void handle(TouchEvent event) {
log("Rectangle: Touch pressed event");
event.consume();
}
});
rect.setOnTouchReleased(new EventHandler<TouchEvent>() {
@Override public void handle(TouchEvent event) {
log("Rectangle: Touch released event");
event.consume();
}
});
タッチ・イベントに応じて実行されるアクションは、ログへのイベントの記録のみです。 タッチ・イベントを使用すると、タッチまたはジェスチャを構成する個々のタッチ・ポイントを掘り下げて追跡できます。 詳細および例は、「タッチ・イベントの使用」を参照してください。
マウス・イベントの処理
マウス・イベントは、マウス・アクションおよびタッチ画面へのタッチによって生成されます。 例5-7に、ジェスチャ・イベントの例におけるMOUSE_PRESSEDイベントおよびMOUSE_RELEASEDイベントに対する楕円のハンドラを示します。
例5-7 マウス・イベントのハンドラの定義
oval.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent event) {
if (event.isSynthesized()) {
log("Ellipse: Mouse pressed event from touch" +
", synthesized: " + event.isSynthesized());
}
event.consume();
}
});
oval.setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent event) {
if (event.isSynthesized()) {
log("Ellipse: Mouse released event from touch" +
", synthesized: " + event.isSynthesized());
}
event.consume();
}
});
マウス押下イベントおよびマウス解放イベントは、タッチ画面へのタッチによってイベントが生成された場合に楕円でのみ処理されます。 四角形のハンドラでは、すべてのマウス押下イベントおよびマウス解放イベントがログに記録されます。
ログの管理
ジェスチャ・イベントの例は、画面上の図形によって処理されたイベントのログを示しています。 ObservableListオブジェクトを使用して各図形に対するイベントを記録し、ListViewオブジェクトを使用してイベントのリストを表示しています。 ログのエントリは50個までに制限されています。 最も新しいエントリがリストの先頭に追加され、最も古いエントリが末尾から削除されます。 ログ管理のコードは、「GestureEvents.java」を参照してください。
アプリケーションで図形を操作し、実行した各ジェスチャによって生成されるイベントを確認してください。


