JavaFX将圆圈绑定到矩形的边缘?

时间:2016-04-29 21:36:41

标签: java javafx javafx-8

我正在尝试将圆圈绑定到矩形的边缘,以便用户可以沿着其中一条边移动圆,但不能移动其他任何边。

截至目前,我正在将圆圈的x和y坐标绑定到矩形上的坐标:

Circle anchor = new Circle();
anchor.centerXProperty().bind(rectangle.xProperty().add(rectangle.widthProperty()));
anchor.centerYProperty().bind(rectangle.yProperty().add(rectangle.heightProperty()));

我如何设置它以便我可以沿着矩形的边缘移动锚点?

1 个答案:

答案 0 :(得分:0)

这不能通过绑定来完成,因为绑定会将target属性绑定到特定值,而不会将值限制为某个范围

要获得所需的效果,您必须在Circle事件处理程序中移动onMouseDragged。以下代码将Circle移动到矩形上与鼠标位置最近的点:

@Override
public void start(Stage primaryStage) {
    Circle circle = new Circle(200, 100, 10, Color.RED);
    Rectangle rect = new Rectangle(200, 100, 200, 300);
    rect.setFill(null);
    rect.setStroke(Color.BLACK);
    rect.setStrokeWidth(3);

    Pane root = new Pane(rect, circle);

    circle.setOnMouseDragged(evt -> {
        Circle c = (Circle) evt.getSource();
        Point2D mousePosition = new Point2D(evt.getX(), evt.getY());
        Point2D targetPosition = closestPosition(c.localToParent(mousePosition), rect);
        c.setCenterX(targetPosition.getX());
        c.setCenterY(targetPosition.getY());
    });

    Scene scene = new Scene(root, 600, 600);

    primaryStage.setScene(scene);
    primaryStage.show();
}

private static class Container {

    final double distance;
    final double targetX;
    final double targetY;

    public Container(double coord1, double coord2, double targetX, double targetY) {
        this.distance = Math.abs(coord1 - coord2);
        this.targetX = targetX;
        this.targetY = targetY;
    }

    public double getDistance() {
        return distance;
    }

}

public static Point2D closestPosition(Point2D point, Rectangle rect) {
    double minX = rect.getX();
    double maxX = minX + rect.getWidth();
    double minY = rect.getY();
    double maxY = minY + rect.getHeight();
    double x = point.getX();
    double y = point.getY();

    boolean outsideXRange = x < minX || x > maxX;
    boolean outsideYRange = y < minY || y > maxY;

    if (!outsideXRange && !outsideYRange) {
        // place point on the edge closest to the point and keep other coordinate
        Container container = Stream.of(
                new Container(x, minX, minX, y),
                new Container(x, maxX, maxX, y),
                new Container(y, minY, x, minY),
                new Container(y, maxY, x, maxY)
        ).min(Comparator.comparingDouble(Container::getDistance)).get();
        return new Point2D(container.targetX, container.targetY);
    } else {
        return new Point2D(
                outsideXRange ? dMin(x, minX, maxX) : x,
                outsideYRange ? dMin(y, minY, maxY) : y);
    }
}

private static double dMin(double target, double value1, double value2) {
    return Math.abs(target - value1) < Math.abs(target - value2) ? value1 : value2;
}