JavaFX Scene Builderで(ファイルの)ドロップ処理を記述する方法。
|
|
(自分のJavaFXアプリの外部から)ファイル等をドラッグして自分のアプリにドロップされた際に、それを受け取ることが出来る。
Scene Builderでドロップ関連イベントに名前を付け、Controllerでその処理を実装する。
ドロップに関連するイベントは以下の4つ。
重要なのはOverとDropped。
Overでドロップを受け付けるかどうか決定し、Droppedで受け取る。
Overでドロップを受け付けるようにしていないと、Droppedイベントは発生しない。
EnteredとExitedは、例えばドロップ対象となるノードの色を変えたい(強調したい)ような場合に使う。
Exnteredで色を変え、Exitedで元に戻す。
ドロップを処理するハンドラー(メソッド)名を、Scene Builderの右側のインスペクターパネルの「Events」の「On Drag Over」「On Drag Dropped」に入れる。
(この際、先頭に「#」を付ける必要がある)
FXMLのコントローラークラスにそのメソッドを記述する。
ドロップを受け付けるかどうかをコーディングする。
Scene Builderで「On Drag Overに入れたのが「#handleDragOver」だとすると、メソッド名は「handleDragOver」になる。
import javafx.scene.input.DragEvent; import javafx.scene.input.Dragboard; import javafx.scene.input.TransferMode;
public void handleDragOver(DragEvent event) { // ファイルの場合だけ受け付ける例 Dragboard db = event.getDragboard(); if (db.hasFiles()) { event.acceptTransferModes(TransferMode.COPY_OR_MOVE); } event.consume(); }
db.hasFiles()で、ファイルがドロップ中なのかどうかを判断できる。
内部では「hasContent(DataFormat.FILES)
」を呼んでおり、色々なドロップオブジェクトに対応できるようだが、
それとは別に、hasFiles()やhasString()の様に、よく使うものについてはメソッド化されている。
ドロップを受け付ける場合はacceptTransferModes()を呼び出し、受け付ける操作を指定する。
例えばCOPYだとコピー、MOVEだと移動。それに応じて、マウスカーソルのアイコンが変わる。
可変長引数で複数の操作方法を指定できるので、COPYとMOVEを両方受け入れる場合は「acceptTransferModes(TransferMode.COPY,
TransferMode.MOVE)
」と書くことも出来る。
COPYとMOVEを両方指定した場合、デフォルトでは「移動」扱いで、ドラッグ中にCtrlキーを押すと「コピー」になる。(もしかするとOS依存かも?)
最後にconsume()を呼んでおく。
Swingにもあったが、イベントを処理したという印なんだろう。
ドロップされた時の処理をコーディングする。
Scene Builderで「On Drag Droppedに入れたのが「#handleDragDropped」だとすると、メソッド名は「handleDragDropped」になる。
import javafx.scene.input.DragEvent; import javafx.scene.input.Dragboard; import javafx.scene.input.TransferMode;
public void handleDragDropped(DragEvent event) { boolean success = false; // ファイルの場合だけ受け付ける例 Dragboard db = event.getDragboard(); if (db.hasFiles()) { List<File> list = db.getFiles(); System.out.println(list); success = true; } event.setDropCompleted(success); event.consume(); }
ファイルがドロップされた場合は、getFiles()でファイル一覧を取得できる。
getFiles()自体はnullを返す可能性があるが、hasFiles()がtrueなら、たぶん必ずnull以外が返るだろう。
ドロップが成功したら、setDropCompleted()でtrueをセットする。
セットしないと失敗扱いになる。
(ドラッグを開始した側へ通知される)
ドラッグ中に、ドロップ対象(ドロップ先)を強調したりすると分かり易い。
Drag Enteredで対象ノード(コンポーネント)のスタイルを変え、Drag Exitedで元に戻す。
Scene Builderの右側のインスペクターパネルの「Events」の「On
Drag Entered」「On Drag Exited」に入れる。
(この際、先頭に「#」を付ける必要がある)
FXMLのコントローラークラスにそのメソッドを記述する。
ドラッグ中のマウスカーソルが入ってきたときに、ドロップ対象のスタイルを変える。
event.getSource()でイベント対象(イベントハンドラーを書いたノード)のオブジェクトが取れる。
イベントハンドラーが書かれているノードとドロップ対象のノードが同じ場合はそれが使える。(が、キャストしないといけないので好みではない)
import javafx.scene.Node; import javafx.scene.input.DragEvent; import javafx.scene.input.Dragboard;
private String saveStyle = null;
public void handleDragEntered(DragEvent event) {
Dragboard db = event.getDragboard();
if (db.hasFiles()) {
Object source = event.getSource();
if (source instanceof Node) {
Node node = (Node)source;
saveStyle = node.getStyle();
node.setStyle("-fx-background-color: blue"); //背景色を変更
}
}
event.consume();
}
マウスカーソルがどっか行ったとき(あるいはドロップした後)にドロップ対象のスタイルを戻す。
import javafx.scene.input.DragEvent;
public void handleDragExited(DragEvent event) { Node node = (Node)event.getSource(); node.setStyle(saveStyle); event.consume(); }
ただ、スタイルを特に何も指定していないノード(コンポーネント)の場合、元々styleは何も入っていないようだ。(getStyle()で空文字列が返る)
つまり元に戻すと言っても空文字列を指定するだけ。
このとき、スタイルによっては元に戻らないこともあるようだ。(Windows版JavaFX2.1では、-fx-background-colorは元に戻ったが、-fx-border-colorは戻らなかった。バグなのかどうか分からないが)