ページ

2013年4月28日日曜日

JavaFX - Dragging gestures (5)

今回は、Platform-supported drag-and-drop gestureについてみていきたいと思います。

Platform-supported drag-and-drop gestureは、アプリケーション間でデータを転送したいときに利用します。データの転送には、クリップボードを利用しますので、JavaFXのアプリケーションでないアプリケーションに対してデータを転送することもできます。

Platform-supported drag-and-drop gestureを開始するためには、DRAG_DETECTEDイベントで、startDragAndDropメソッドを呼び出します。このとき、Dragboardクラスのインスタンスが返されますので、ドラッグアンドドロップで転送したいデータを、ClipboardContentを利用して設定します。例えば、TextAreaの選択されているテキストの内容を転送したい場合は、DRAG_DETECTEDイベントで以下のようにします。

@Override
public void handle(MouseEvent event) {
    TextArea source = (TextArea)event.getSource();
    if (source.getSelectedText().isEmpty()) { return; }

    Dragboard board = source.startDragAndDrop(TransferMode.COPY_OR_MOVE);
    ClipboardContent content = new ClipboardContent();
    content.putString(source.getSelectedText());
    board.setContent(content);
    event.consume();
}

startDragAndDropメソッドを呼び出して、Dragboardに何も設定しない場合は、Platform-supported drag-and-drop gestureは開始されません。

Platform-supported drag-and-drop gestureが開始されると、DragEventが発生しますので、このイベントにハンドラを追加して、処理を行います。

DragEventのイベントタイプには、以下のものがあります。

  • DRAG_DONE
  • DRAG_DROPPED
  • DRAG_ENTERED
  • DRAG_ENTERED_TARGET
  • DRAG_EXITED
  • DRAG_EXITED_TARGET
  • DRAG_OVER

基本的には、ドラッグ元でDRAG_DONEイベントにハンドラを追加し、ドラッグ先で残りのイベントにハンドラを追加します。DRAG_ENTERED_TARGETとDRAG_EXITED_TARGETについては、MouseEventやMouseDragEventのときと同様に、キャプチャリングフェーズあるいはバブリングフェーズでハンドラを追加したいときに利用します。

ドラッグ先では、DRAG_OVERイベントが発生したときに、Dragboardに設定されているデータを確認し、ドロップ対象とするかどうかの判定を、acceptTransferModesメソッドを呼び出すことによって行います。このメソッドの引数には、どのTransferModeでドロップするかを指定します。例えば、文字列のデータを移動させるためのドロップ対象とする場合は、DRAG_OVERイベントで以下のようにします。

@Override
public void handle(DragEvent event) {
    Dragboard board = event.getDragboard();
    if (board.hasString()) {
        event.acceptTransferModes(TransferMode.MOVE);
    }
    event.consume();
}

ドロップ対象とした場合、ドラッグ先のノード上でマウスをリリースすると、DRAG_DROPPEDイベントが発生しますので、このイベントにハンドラを追加して、ドロップしたときの処理を行います。

@Override
public void handle(DragEvent event) {
    Dragboard board = event.getDragboard();
    if (board.hasString()) {
        // ドロップ時の処理を実装
        event.setDropCompleted(true);
    }
    event.consume();
}

ドロップの処理が正常に行われた場合は、DragEventのsetDropCompletedメソッドの引数にtrueを指定して呼び出しておきます。

ドロップが行われると、正常に終了したかどうかに関わらず、ドラッグ元にDRAG_DONEイベントが発生します。ドロップが正常に行われたかどうかは、DragEventのgetTransferModeメソッドで、TransferModeが取得できたかどうかで判断します。ドロップ対象ノード以外にドロップしたか、ESCでキャンセルされたか、setDropCompletedメソッドでfalseが設定された場合は、取得したTransferModeがNULLとなります。それ以外の場合は、ドロップされたときのTransferModeが取得されますので、取得したTransferModeの値に対する処理を行います。基本的には、TransferMode.MOVEを取得したときに、ドラッグしたデータを削除することになります。例えば、TextAreaの選択されているテキストの内容を転送していた場合に、TransferMode.MOVEでドロップした場合は、DRAG_DONEイベントで以下のようにします。

@Override
public void handle(DragEvent event) {
    if (event.getTransferMode() == TransferMode.MOVE) {
        TextArea source = (TextArea)event.getSource();
        source.deleteText(source.getSelection());
    }
    event.consume();
}

ClipboardContentに設定できるデータは、DataFormatで定義されている以下のものがあります。

  • FILES
  • HTML
  • IMAGE
  • PLAIN_TEXT
  • RTF
  • URL

上記以外にも、DataFormatクラスのインスタンスを作成することによって、独自のデータを設定することもできます。ただし、設定するデータはシリアル化できるものである必要があります。

今回は、Platform-supported drag-and-drop gestureについて、どのようにして行うかをみていきました。次回は、これを利用したものを何か作ってみたいと思います。