7 ドラッグ・アンド・ドロップ操作
このドキュメントでは、JavaFXアプリケーションにドラッグ・アンド・ドロップ機能を実装する方法、ドラッグ・アンド・ドロップ・ジェスチャに関連するオブジェクト、転送可能なデータの型、およびドラッグ・アンド・ドロップ・ジェスチャの実行時に発生するイベントについて説明します。
また、このドキュメントでは、使用されているAPIおよび説明で取り上げられているマテリアルを例示するコード・サンプルも紹介します。
ドラッグ・アンド・ドロップ操作の対象となるオブジェクトおよびデータ型
ドラッグ・アンド・ドロップ操作とは、2つのオブジェクト(ジェスチャ・ソースおよびジェスチャ・ターゲット)間のデータ転送のことです。次のオブジェクトがジェスチャ・ソースおよびジェスチャ・ターゲットになります。
-
ノード
-
シーン
ジェスチャ・ソースおよびジェスチャ・ターゲットは、両方が単一のJavaFXアプリケーションに属していても、2つの異なるJavaFXアプリケーションまたはJavaクライアント・アプリケーションに属していてもかまいません。さらに、JavaFXアプリケーションとサード・パーティ(ネイティブ)アプリケーション(Windows Explorerやデスクトップなど)との間にドラッグ・アンド・ドロップを実装することもできます。
ドラッグ・アンド・ドロップ・ジェスチャは、「ユーザーがジェスチャ・ソースでマウス・ボタンをクリックし、マウスをドラッグし、ジェスチャ・ターゲットでマウス・ボタンを放す」という動作です。ユーザーがデータをドラッグするときには、データのドロップ可否を示す視覚フィードバックが提供され、ドロップ可能な場所を認識するヒントとなります。
データはダッシュボードを使用して転送されます。このダッシュボードは、システム・クリップボードと同じインタフェースを持ちますが、ドラッグ・アンド・ドロップ・データ転送にのみ使用されます。
ドラッグ・アンド・ドロップ・ジェスチャでは、テキスト、イメージ、URL、ファイル、バイト、文字列など、様々なタイプのデータを転送できます。
javafx.scene.input.DragEvent
クラスは、ドラッグ・アンド・ドロップ・ジェスチャの実装に使用される基本クラスです。javafx.scene.input
パッケージ内の特定のメソッドおよびその他のクラスの詳細は、APIのドキュメントを参照してください。
基本的なドラッグ・アンド・ドロップ・ジェスチャの実装
HelloDragAndDrop
サンプル・アプリケーションを使用して、基本的なドラッグ・アンド・ドロップ機能を実装する方法について説明します。例7-1に示すように、2つのテキスト・ノードがジェスチャ・ソースおよびジェスチャ・ターゲットとして定義されています。
例7-1
final Text source = new Text(50, 100, "DRAG ME"); final Text target = new Text(300, 100, "DROP HERE");
ソースでのドラッグ・アンド・ドロップ・ジェスチャの開始
ドラッグ・アンド・ドロップ・ジェスチャは、ジェスチャ・ソースに対してDRAG_DETECTED
イベントのハンドラ内からstartDragAndDrop
メソッドをコールすることによってのみ開始できます。ここでは、ジェスチャ・ソースでサポートされる転送モードを定義し、転送対象データをダッシュボード上に配置しています。
例7-2に、onDragDetected
ハンドラの実装を示します。
例7-2
source.setOnDragDetected(new EventHandler<MouseEvent>() { public void handle(MouseEvent event) { /* drag was detected, start a drag-and-drop gesture*/ /* allow any transfer mode */ Dragboard db = source.startDragAndDrop(TransferMode.ANY); /* Put a string on a dragboard */ ClipboardContent content = new ClipboardContent(); content.putString(source.getText()); db.setContent(content); event.consume(); } });
startDragAndDrop
メソッドには、ジェスチャ・ソースでサポートされる一連の転送モードを渡します。使用可能な転送モードを任意に組み合せて渡すことができます。TransferMode.COPY
を渡した場合、ジェスチャ・ソースではコピーのみがサポートされ、移動と参照はサポートされません。
ターゲットでのDRAG_OVERイベントの処理
ドラッグ・アンド・ドロップ・ジェスチャが開始された後、データのドロップ先となるターゲット候補として任意のノードまたはシーン上にマウスがドラッグされます。DRAG_OVER
イベント・ハンドラを実装することによって、データのドロップ先として許容するオブジェクトを指定します。
DRAG_OVER
イベント・ハンドラの重要性に留意してください。ドラッグ・アンド・ドロップ操作が正常に実行されるようにするには、イベント発生時にacceptTransferModes(TransferMode...)
メソッドをコールするDRAG_OVER
イベント・ハンドラを実装し、ターゲットで受け入れられる転送モードをこのメソッドに渡す必要があります。渡した転送モードがいずれもジェスチャ・ソースでサポートされていない場合、ターゲット候補はそのドラッグ・アンド・ドロップ・ジェスチャに適していません。
イベントを受け入れるかどうかを判断する際には、ダッシュボード上にあるデータの型を考慮する必要があります。ダッシュボードに格納されているデータにアクセスするには、event.getDragboard()
メソッドを使用します。
例7-3に、DRAG_OVER
イベント・ハンドラの実装を示します。
例7-3
target.setOnDragOver(new EventHandler<DragEvent>() { public void handle(DragEvent event) { /* data is dragged over the target */ /* accept it only if it is not dragged from the same node * and if it has a string data */ if (event.getGestureSource() != target && event.getDragboard().hasString()) { /* allow for moving */ event.acceptTransferModes(TransferMode.MOVE); } event.consume(); } });
ジェスチャ・ターゲットでの視覚フィードバックの提供
ドラッグ・アンド・ドロップ・ジェスチャの実行時に、ユーザーがそのジェスチャに適したターゲット上にマウス・ポインタを置くと、ドロップ可能な場所を認識するヒントとして、一般にターゲットの外観が変更されます。
ドラッグ・ジェスチャがジェスチャ・ターゲット候補の境界に入ると、ターゲットにDRAG_ENTERED
イベントが送信されます。ドラッグ・ジェスチャがターゲット候補の境界から出ると、ターゲットにDRAG_EXITED
イベントが送信されます。ユーザーに視覚フィードバックを提供するには、DRAG_ENTERED
およびDRAG_EXITED
イベント・ハンドラを使用してターゲットの外観を変更します。
例7-4に、視覚フィードバックとしてテキスト色の変更を実装する方法を示します。
例7-4
target.setOnDragEntered(new EventHandler<DragEvent>() { public void handle(DragEvent event) { /* the drag-and-drop gesture entered the target */ /* show to the user that it is an actual gesture target */ if (event.getGestureSource() != target && event.getDragboard().hasString()) { target.setFill(Color.GREEN); } event.consume(); } });
ダッシュボードの内容検証の重要性に留意してください。ターゲットの外観が変更されるのは、ダッシュボードに適切な形式のデータ(この例では文字列)が含まれている場合のみです。
例7-5に、テキストの外観を元に戻すためのDRAG_EXITED
イベント・ハンドラの実装を示します。
ターゲットでのDRAG_DROPPEDイベントの処理
ジェスチャ・ターゲットで前のDRAG_OVER
イベントが受け入れられた後(ジェスチャ・ソースでサポートされている転送モードに対応している場合)、マウス・ボタンが放されると、DRAG_DROPPED
イベントがジェスチャ・ターゲットに送信されます。DRAG_DROPPED
イベント・ハンドラでは、イベント発生時にsetDropCompleted(Boolean)
メソッドをコールしてドラッグ・アンド・ドロップ・ジェスチャを完了する必要があります。そうしないと、ジェスチャは失敗とみなされます。
例7-6に、DRAG_DROPPED
イベント・ハンドラの実装を示します。
例7-6
target.setOnDragDropped(new EventHandler<DragEvent>() { public void handle(DragEvent event) { /* data dropped */ /* if there is a string data on dragboard, read it and use it */ Dragboard db = event.getDragboard(); boolean success = false; if (db.hasString()) { target.setText(db.getString()); success = true; } /* let the source know whether the string was successfully * transferred and used */ event.setDropCompleted(success); event.consume(); } });
ソースでのDRAG_DONEイベントの処理
ドラッグ・アンド・ドロップ・ジェスチャが完了したら、ジェスチャの完了状況を通知するためにジェスチャ・ソースにDRAG_DONE
イベントが送信されます。DRAG_DONE
イベント・ハンドラでは、イベント発生時にgetTransferMode
メソッドをコールして転送モードを取得します。転送モードがNULL
の場合は、データ転送が実行されなかったことを意味しています。例7-7に示すように、モードがMOVE
の場合は、ジェスチャ・ソース上のデータがクリアされます。
カスタム・データのドラッグ
同様に、カスタム・データに対するドラッグ・アンド・ドロップ・ジェスチャを実装できます。例7-8に示すように、カスタム・データ型を定義します。
例7-8
/** The custom format */ private static final DataFormat customFormat = new DataFormat("helloworld.custom");
カスタム・データをダッシュボード上に配置する場合は、そのデータ型を指定します。データはシリアライズ可能である必要があります。
ダッシュボードからデータを読み取るときには、適切なキャスティングが必要になります。