JavaFXのドラッグの動作についてみていきたいと思います。
JavaFXのドラッグの動作には、以下の3つのタイプがあります。
- Simple press-drag-release gesture
- Full press-drag-release gesture
- Platform-supported drag-and-drop gesture
これらの動作は、MOUSE_PRESSEDイベントで開始し、MOUSE_RELEASEDイベントで終了することになり、Simple press-drag-release gestureがデフォルトの動作になります。
まずは、Simple press-drag-release gestureからみていきたいと思います。
この動作については、ノードの大きさを変更したり、ノードの位置をドラッグして移動したりするときのように、対象となるノードのみの操作で、他のノードと関連しないような操作を行いたいときに利用します。
MOUSE_PRESSEDイベントが発生したノードに対して、MOUSE_RELEASEDイベントが発生するまで、そのノードに対してマウスイベントが発生しますので、基本的には、MOUSE_PRESSEDイベントで、ドラッグしたいノードに対して初期処理を行い、MOUSE_DRAGGEDイベントで、ドラッグしたときの処理を行い、MOUSE_RELEASEDイベントで、終了処理を行うことになります。
以下のような、1つのノードの位置をドラッグで移動するものを作成してみたいと思います。
シーン上に1つのCircleがあり、それを操作する単純なものになります。
まずは、FXMLで以下のようにViewを定義します。
<Scene xmlns:fx="http://javafx.com/fxml"
fx:id="scene"
width="640" height="480">
<stylesheets>
<URL value="@NodeDragDemoStyle.css"/>
</stylesheets>
<Pane>
<Circle fx:id="draggableCircle"
centerX="100" centerY="100" radius="30"/>
</Pane>
</Scene>
次に、コントローラクラスを定義し、Circleのドラッグに対する動作を実装します。
public class NodeDragDemoSceneController {
@FXML
private Scene scene;
@FXML
private Circle draggableCircle;
private double dragAnchorX;
private double dragAnchorY;
public void performOn(Stage stage) {
stage.setScene(scene);
stage.setTitle("Node Drag Demo");
stage.sizeToScene();
stage.centerOnScreen();
stage.show();
}
@FXML
protected void initialize() {
draggableCircle.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
Node node = (Node)mouseEvent.getSource();
dragAnchorX = mouseEvent.getSceneX() - node.getLayoutX();
dragAnchorY = mouseEvent.getSceneY() - node.getLayoutY();
}
});
draggableCircle.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
Node node = (Node)mouseEvent.getSource();
node.setLayoutX(mouseEvent.getSceneX() - dragAnchorX);
node.setLayoutY(mouseEvent.getSceneY() - dragAnchorY);
}
});
}
}
ノードの位置を変更するには、layoutXとlayoutYを変更することによって行っています。ドラッグしたときのマウスの位置の変化分をlayoutXとlayoutYに反映するようにしています。
MOUSE_PRESSEDイベントで、マウスのシーンに対する位置からノードのlayoutX, layoutYを引いた値を保持しておき、MOUSE_DRAGGEDイベントで、ドラッグしたときのマウスのシーンに対する位置から保持していた値を引くことによって、ドラッグ開始時のlayoutX, layoutYに、ドラッグしたときのマウスの移動量を追加するようにしています。今回は、終了処理として特に何も行いませんので、MOUSE_RELEASEDイベントは設定しませんでした。
あとは、Applicationクラスを作成しておきます。
public class NodeDragDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
FXController.of(new NodeDragDemoSceneController())
.fromDefaultLocation()
.load()
.performOn(primaryStage);
}
public static void main(String... args) {
launch(args);
}
}
FXControllerについては、こちらの記事を参照してください。
ドラッグの動作として、Simple press-drag-release gestureについてみていきました。ドラッグの動作としては基本的に、MOUSE_PRESSEDイベントで初期処理、MOUSE_DRAGGEDイベントでドラッグ中の処理、MOUSE_RELEASEDイベントで終了処理を実装すればよさそうです。次回は、このドラッグでノードを移動する動作を、コントローラクラスに直接記述するのではなく、再利用可能となるようなユーティリティクラスとして作成することを考えてみます。