形状旋转 - 锚点不跟随 - JavaFX

Shape Rotation - Anchors Do Not Follow - JavaFX

我创建了一个既可移动又可调整大小的矩形。我需要为我成功完成的形状实施旋转。但是,当我旋转形状时,锚点不会跟随。谁能就我做错了什么或如何解决这个问题给我一些指导?

轮换前:

旋转后:

public Rectangle createDraggableRectangle(double x, double y, double width, double height) {
    final double handleRadius = 20 ;
    final double handleRadius2 = 30 ;

    Rectangle rect = new Rectangle(x, y, width, height);

    // top left resize handle:
    Circle resizeHandleNW = new Circle(handleRadius, Color.RED);
    // bind to top left cornerof Rectangle:
    resizeHandleNW.centerXProperty().bind(rect.xProperty());
    resizeHandleNW.centerYProperty().bind(rect.yProperty());

    // bottom right resize handle:
    Circle resizeHandleSE = new Circle(handleRadius, Color.RED);
    // bind to bottom right corner of Rectangle:
    resizeHandleSE.centerXProperty().bind(rect.xProperty().add(rect.widthProperty()));
    resizeHandleSE.centerYProperty().bind(rect.yProperty().add(rect.heightProperty()));

    // move handle:
    Circle moveHandle = new Circle(handleRadius2,Color.RED);
    moveHandle.setOpacity(0.0);
    // bind to bottom center of Rectangle:
    moveHandle.centerXProperty().bind(rect.xProperty().add(rect.widthProperty().divide(2)));
    moveHandle.centerYProperty().bind(rect.yProperty().add(rect.heightProperty().divide(2)));

    // force circles to live in same parent as rectangle:
    rect.parentProperty().addListener((obs, oldParent, newParent) -> {
        for (Circle c : Arrays.asList(resizeHandleNW, resizeHandleSE, moveHandle)) {
            Pane currentParent = (Pane)c.getParent();
            if (currentParent != null) {
                currentParent.getChildren().remove(c);
            }
            ((Pane)newParent).getChildren().add(c);
        }
    });

    Wrapper<Point2D> mouseLocation = new Wrapper<>();

    setUpDragging(resizeHandleNW, mouseLocation) ;
    setUpDragging(resizeHandleSE, mouseLocation) ;
    setUpDragging(moveHandle, mouseLocation) ;

    resizeHandleNW.setOnMouseDragged(event -> {
        if (mouseLocation.value != null) {
            double deltaX = event.getSceneX() - mouseLocation.value.getX();
            double deltaY = event.getSceneY() - mouseLocation.value.getY();
            double newX = rect.getX() + deltaX ;
            if (newX >= handleRadius
                    && newX <= rect.getX() + rect.getWidth() - handleRadius) {
                rect.setX(newX);
                rect.setWidth(rect.getWidth() - deltaX);
            }
            double newY = rect.getY() + deltaY ;
            if (newY >= handleRadius
                    && newY <= rect.getY() + rect.getHeight() - handleRadius) {
                rect.setY(newY);
                rect.setHeight(rect.getHeight() - deltaY);
            }
            mouseLocation.value = new Point2D(event.getSceneX(), event.getSceneY());
        }
    });

    resizeHandleSE.setOnMouseDragged(event -> {
        if (mouseLocation.value != null) {
            double deltaX = event.getSceneX() - mouseLocation.value.getX();
            double deltaY = event.getSceneY() - mouseLocation.value.getY();
            double newMaxX = rect.getX() + rect.getWidth() + deltaX ;
            if (newMaxX >= rect.getX()
                    && newMaxX <= rect.getParent().getBoundsInLocal().getWidth() - handleRadius) {
                rect.setWidth(rect.getWidth() + deltaX);
            }
            double newMaxY = rect.getY() + rect.getHeight() + deltaY ;
            if (newMaxY >= rect.getY()
                    && newMaxY <= rect.getParent().getBoundsInLocal().getHeight() - handleRadius) {
                rect.setHeight(rect.getHeight() + deltaY);
            }
            mouseLocation.value = new Point2D(event.getSceneX(), event.getSceneY());
        }
    });

    moveHandle.setOnMouseDragged(event -> {
        if (mouseLocation.value != null) {
            double deltaX = event.getSceneX() - mouseLocation.value.getX();
            double deltaY = event.getSceneY() - mouseLocation.value.getY();
            double newX = rect.getX() + deltaX ;
            double newMaxX = newX + rect.getWidth();
            if (newX >= handleRadius
                    && newMaxX <= rect.getParent().getBoundsInLocal().getWidth() - handleRadius) {
                rect.setX(newX);
            }
            double newY = rect.getY() + deltaY ;
            double newMaxY = newY + rect.getHeight();
            if (newY >= handleRadius
                    && newMaxY <= rect.getParent().getBoundsInLocal().getHeight() - handleRadius) {
                rect.setY(newY);
            }
            mouseLocation.value = new Point2D(event.getSceneX(), event.getSceneY());
        }

    });

    return rect ;
}

private void setUpDragging(Circle circle, Wrapper<Point2D> mouseLocation) {

    circle.setOnDragDetected(event -> {
        circle.getParent().setCursor(Cursor.CLOSED_HAND);
        mouseLocation.value = new Point2D(event.getSceneX(), event.getSceneY());
    });

    circle.setOnMouseReleased(event -> {
        circle.getParent().setCursor(Cursor.DEFAULT);
        mouseLocation.value = null ;
    });
}

static class Wrapper<T> { T value ; }

矩形Class^

public void rotateObject(ActionEvent event) throws IOException {

    rect.setRotate(90);
    rect.getTransforms().add(new Rotate(45, rect.getBoundsInParent().getMinX() +
            (rect.getBoundsInLocal().getWidth() / 4),
             rect.getBoundsInParent().getMinY() + rect.getBoundsInLocal().getHeight() / 4));

}

^ 用于旋转的方法。

将"handles"和矩形拼成一个Group,旋转组而不是矩形:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;

public class DraggingRectangleExample extends Application {

    private Node rect ;

    @Override
    public void start(Stage primaryStage) {
        rect = createDraggableRectangle(50, 50, 50, 150);
        Pane pane = new Pane(rect);
        pane.setMinSize(600, 600);
        Button button = new Button("Rotate");
        button.setOnAction(e -> rotateObject());

        BorderPane root = new BorderPane(pane);
        BorderPane.setMargin(button, new Insets(10));
        BorderPane.setAlignment(button, Pos.CENTER);
        root.setBottom(button);

        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

    public void rotateObject()  {

        rect.setRotate(90);
        rect.getTransforms().add(new Rotate(45, rect.getBoundsInParent().getMinX() +
                (rect.getBoundsInLocal().getWidth() / 4),
                 rect.getBoundsInParent().getMinY() + rect.getBoundsInLocal().getHeight() / 4));

    }

    public Group createDraggableRectangle(double x, double y, double width, double height) {
        final double handleRadius = 20 ;
        final double handleRadius2 = 30 ;

        Rectangle rect = new Rectangle(x, y, width, height);

        // top left resize handle:
        Circle resizeHandleNW = new Circle(handleRadius, Color.RED);
        // bind to top left cornerof Rectangle:
        resizeHandleNW.centerXProperty().bind(rect.xProperty());
        resizeHandleNW.centerYProperty().bind(rect.yProperty());

        // bottom right resize handle:
        Circle resizeHandleSE = new Circle(handleRadius, Color.RED);
        // bind to bottom right corner of Rectangle:
        resizeHandleSE.centerXProperty().bind(rect.xProperty().add(rect.widthProperty()));
        resizeHandleSE.centerYProperty().bind(rect.yProperty().add(rect.heightProperty()));

        // move handle:
        Circle moveHandle = new Circle(handleRadius2,Color.RED);
        moveHandle.setOpacity(0.0);
        // bind to bottom center of Rectangle:
        moveHandle.centerXProperty().bind(rect.xProperty().add(rect.widthProperty().divide(2)));
        moveHandle.centerYProperty().bind(rect.yProperty().add(rect.heightProperty().divide(2)));

        // force circles to live in same parent as rectangle:
//      rect.parentProperty().addListener((obs, oldParent, newParent) -> {
//          for (Circle c : Arrays.asList(resizeHandleNW, resizeHandleSE, moveHandle)) {
//              Pane currentParent = (Pane)c.getParent();
//              if (currentParent != null) {
//                  currentParent.getChildren().remove(c);
//              }
//              ((Pane)newParent).getChildren().add(c);
//          }
//      });

        Group group = new Group(rect, resizeHandleNW, resizeHandleSE, moveHandle);


        Wrapper<Point2D> mouseLocation = new Wrapper<>();

        setUpDragging(resizeHandleNW, mouseLocation) ;
        setUpDragging(resizeHandleSE, mouseLocation) ;
        setUpDragging(moveHandle, mouseLocation) ;

        resizeHandleNW.setOnMouseDragged(event -> {
            if (mouseLocation.value != null) {
                double deltaX = event.getSceneX() - mouseLocation.value.getX();
                double deltaY = event.getSceneY() - mouseLocation.value.getY();
                double newX = rect.getX() + deltaX ;
                if (newX >= handleRadius
                        && newX <= rect.getX() + rect.getWidth() - handleRadius) {
                    rect.setX(newX);
                    rect.setWidth(rect.getWidth() - deltaX);
                }
                double newY = rect.getY() + deltaY ;
                if (newY >= handleRadius
                        && newY <= rect.getY() + rect.getHeight() - handleRadius) {
                    rect.setY(newY);
                    rect.setHeight(rect.getHeight() - deltaY);
                }
                mouseLocation.value = new Point2D(event.getSceneX(), event.getSceneY());
            }
        });

        resizeHandleSE.setOnMouseDragged(event -> {
            if (mouseLocation.value != null) {
                double deltaX = event.getSceneX() - mouseLocation.value.getX();
                double deltaY = event.getSceneY() - mouseLocation.value.getY();
                double newMaxX = rect.getX() + rect.getWidth() + deltaX ;
                if (newMaxX >= rect.getX()
                        && newMaxX <= group.getParent().getBoundsInLocal().getWidth() - handleRadius) {
                    rect.setWidth(rect.getWidth() + deltaX);
                }
                double newMaxY = rect.getY() + rect.getHeight() + deltaY ;
                if (newMaxY >= rect.getY()
                        && newMaxY <= group.getParent().getBoundsInLocal().getHeight() - handleRadius) {
                    rect.setHeight(rect.getHeight() + deltaY);
                }
                mouseLocation.value = new Point2D(event.getSceneX(), event.getSceneY());
            }
        });

        moveHandle.setOnMouseDragged(event -> {
            if (mouseLocation.value != null) {
                double deltaX = event.getSceneX() - mouseLocation.value.getX();
                double deltaY = event.getSceneY() - mouseLocation.value.getY();
                double newX = rect.getX() + deltaX ;
                double newMaxX = newX + rect.getWidth();
                if (newX >= handleRadius
                        && newMaxX <=group.getParent().getBoundsInLocal().getWidth() - handleRadius) {
                    rect.setX(newX);
                }
                double newY = rect.getY() + deltaY ;
                double newMaxY = newY + rect.getHeight();
                if (newY >= handleRadius
                        && newMaxY <=group.getParent().getBoundsInLocal().getHeight() - handleRadius) {
                    rect.setY(newY);
                }
                mouseLocation.value = new Point2D(event.getSceneX(), event.getSceneY());
            }

        });


        return group ;
    }

    private void setUpDragging(Circle circle, Wrapper<Point2D> mouseLocation) {

        circle.setOnDragDetected(event -> {
            circle.getParent().setCursor(Cursor.CLOSED_HAND);
            mouseLocation.value = new Point2D(event.getSceneX(), event.getSceneY());
        });

        circle.setOnMouseReleased(event -> {
            circle.getParent().setCursor(Cursor.DEFAULT);
            mouseLocation.value = null ;
        });
    }



    static class Wrapper<T> { T value ; }

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