Dan Hayes
Dan Hayes

Reputation: 97

JavaFX ImageView rotation changes drag and drop

So I have an ImageView that can be dragged and dropped using the mouse and rotated 90 degrees with a button click. Both of these things work when done independently (so the ImageView can be rotated or moved, not both). When i rotate the ImageView and attempt to move it, it seems to move randomly.

I rotate the ImageView using:

imageView.setRotate(90);

This results in the seemingly random movement i was talking about.

I also tried to rotate the ImageView using:

imageView.getTransforms().add(new Rotate(rotation, position + (width / 2), position + (height / 2));

Position being the images position on screen. Width and height being the ImageView's width and height.

This worked for the most part (the ImageView no longer moves in an unexpected way), however now it can be moved and placed outside the bounds of the Pane (javafx.scene.layout.Pane), which is its parent.

The way the ImageView is kept within the bounds is:

imageView.setOnMouseDragged(new EventHandler<MouseEvent>(){
            public void handle(MouseEvent e) {
                if(!e.isPrimaryButtonDown()) return;

                ImageView iv = (ImageView) e.getSource();

                if(e.getX() > iv.getParent().getTranslateX()) iv.setX(e.getX());
                if(e.getY() > iv.getParent().getTranslateY()) iv.setY(e.getY());
            }
        });

The Parent to this is the Pane stated earlier. This works fine up until the ImageView is rotated.

I'm not sure where to go from here so I'm grateful for any help. Thanks.


EDIT TO ORIGINAL QUESTION:

Using the second method of rotation :

imageView.getTransforms().add(new Rotate(rotation, position + (width / 2), position + (height / 2));

This method works apart from the fact that the translations for x and y change i rotate the ImageView. For example if i move my mouse right on an image that is rotated 90 degrees then then the position for e.getX() in my MouseDraggedEvent doesn't change but e.getY() decreases. This indicates that the way e.getX() and e.getY() are dependent on the rotation of the ImageView.

Is there a way to rotate without effecting the ImageView's x and y coords?

Upvotes: 0

Views: 1550

Answers (1)

James_D
James_D

Reputation: 209330

The values e.getX() and e.getY() are in the coordinate system of the image view; that coordinate system is still local to the image view after rotation. Consequently you're setting the x-coordinate of the image view to something that, after rotation, really has more to do with the y-coordinate (in some non-trivial way).

You should calculate dragging by computing the amount the mouse has moved relative to something fixed: e.g. the scene.

Here is a SSCCE that works (double-click to rotate):

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class ImageTransformTest extends Application {

    @Override
    public void start(Stage primaryStage) {
        ImageView arrow = new ImageView(createImage());
        Pane pane = new Pane(arrow);
        pane.setMinSize(600,  600);

        new Dragger(arrow) ;
        arrow.setOnMouseClicked(e -> {
            if (e.getClickCount() == 2) {
                arrow.setRotate(arrow.getRotate() + 90);
            }
        });

        Scene scene = new Scene(pane) ;
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private static class Dragger {
        private double x ;
        private double y ;
        Dragger(ImageView imageView) {
            imageView.setOnMousePressed(e -> {
                x = e.getSceneX();
                y = e.getSceneY();
            });
            imageView.setOnMouseDragged(e -> {
                double deltaX = e.getSceneX() - x ;
                double deltaY = e.getSceneY() - y ;
                imageView.setX(imageView.getX() + deltaX);
                imageView.setY(imageView.getY() + deltaY);
                x = e.getSceneX() ;
                y = e.getSceneY() ;
            });
        }
    }

    private Image createImage() {
        WritableImage image = new WritableImage(100, 100);
        for (int y = 0 ; y < 40 ; y++) {
            for (int x = 0 ; x < 50 - 50 * y / 40 ; x++) {
                image.getPixelWriter().setColor(x, y, Color.TRANSPARENT);
            }
            for (int x = 50 - 50 * y / 40 ; x < 50 + 50 * y / 40 ; x ++) {
                image.getPixelWriter().setColor(x, y, Color.BLUE);
            }
            for (int x = 50 + 50 * y ; x < 100 ; x++) {
                image.getPixelWriter().setColor(x, y, Color.TRANSPARENT);
            }
        }
        for (int y = 40 ; y < 100 ; y++) {
            for (int x = 0 ; x < 100 ; x++) {
                image.getPixelWriter().setColor(x, y, x < 30 || x > 70 ? Color.TRANSPARENT : Color.BLUE);
            }
        }

        return image ;
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Upvotes: 1

Related Questions