5

I have a polygon (triangle shape). I want to make it draggable with mouse. Below is the code that I tried, but with this code I am not able to drag it smoothly. Please let me know how can I achieved to make it draggable smoothly.

    public void start(Stage primaryStage) throws Exception {
    AnchorPane pane = new AnchorPane();

    final Polygon polygon   = new Polygon();
    polygon.getPoints().addAll(new Double[]{
            50.0,  50.0,
            30.0, 70.0,
            70.0, 70.0 });

    pane.getChildren().add(polygon);

    Scene scene = new Scene(pane, 200, 200, Color.WHITE);
    primaryStage.setScene(scene);
    primaryStage.show();

    polygon.setOnMouseDragged(new EventHandler<MouseEvent>() {

        @Override
        public void handle(MouseEvent event) {
            polygon.setLayoutX(event.getX());
            polygon.setLayoutY(event.getY());

        }
    });
  } 
Angom
  • 721
  • 1
  • 11
  • 27

1 Answers1

8

The problem is that the coordinates of the mouse event (event.getX() and event.getY()) are relative to the polygon; whereas the layoutX and layoutY of the polygon are relative to the parent of the polygon (i.e. the pane).

There are lots of ways to do this, but all involve measuring the coordinates of the event relative to something fixed (the Scene, for example) and incrementing the layoutX and layoutY by the change in those coordinates.

Something like this will work:

    final ObjectProperty<Point2D> mousePosition = new SimpleObjectProperty<>();

    polygon.setOnMousePressed(new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent event) {
            mousePosition.set(new Point2D(event.getSceneX(), event.getSceneY()));
        }
    });

    polygon.setOnMouseDragged(new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent event) {
            double deltaX = event.getSceneX() - mousePosition.get().getX();
            double deltaY = event.getSceneY() - mousePosition.get().getY();
            polygon.setLayoutX(polygon.getLayoutX()+deltaX);
            polygon.setLayoutY(polygon.getLayoutY()+deltaY);
            mousePosition.set(new Point2D(event.getSceneX(), event.getSceneY()));
        }
    });
James_D
  • 201,275
  • 16
  • 291
  • 322
  • Why does it not work to simply use polygon.setLayoutX(e.getSceneX()); and similarly for the y-variable? When I did that, the shape always trailed to the right and below my mouse. –  Apr 05 '15 at 21:58
  • `layoutX` is the location of the polygon (the point at the top left of its bounds) relative to its parent. `e.getSceneX()` is the location of the mouse relative to the scene. If the parent were the root of the scene, *and* you clicked the mouse at the top left point of its bounds, this would work. Otherwise it would be offset by some amount. – James_D Apr 05 '15 at 22:28
  • What accounts for the large distance between mouse and polygon? The mouse (on my screen) is well outside the bounding box that I would think goes with the polygon (the smallest one containing it). It appears to be about 20 px left and 40 px above the left-top corner of the bounding box. Is the bounding box larger than I think for some reason? –  Apr 06 '15 at 00:00
  • The bounding box of a Shape is a bit counterintuitive. I believe the layout coordinates in the parent's coordinate space, in the absence of any transforms, correspond to the (0, 0) coordinate of the shape in its own coordinate system. At any rate, you should transform the shape by an amount that is computed relative to some fixed coordinate system at different occurrences of the mouse events. – James_D Apr 06 '15 at 00:33
  • I ask because I have been having difficultly getting ImageView objects (or Rectangle objects for that matter) to move around according to mouse clicks. They seem to go wherever they want to... I have another question about the code you gave. I'm a little confused about the Property instances that seem to be everywhere in JavaFX code. In this case, are you putting the Point2D into a property so that its reference variable can be made final (even though it will be mutated)? Is there a reason non-final variables can't be used directly? And do people just wrap objects in properties for binding? –  Apr 06 '15 at 00:43
  • *I mean besides the reason that the compiler won't allow it, of course. –  Apr 06 '15 at 00:43