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イベントで終了処理を実装すればよさそうです。次回は、このドラッグでノードを移動する動作を、コントローラクラスに直接記述するのではなく、再利用可能となるようなユーティリティクラスとして作成することを考えてみます。