我正在尝试将圆圈绑定到矩形的边缘,以便用户可以沿着其中一条边移动圆,但不能移动其他任何边。
截至目前,我正在将圆圈的x和y坐标绑定到矩形上的坐标:
Circle anchor = new Circle();
anchor.centerXProperty().bind(rectangle.xProperty().add(rectangle.widthProperty()));
anchor.centerYProperty().bind(rectangle.yProperty().add(rectangle.heightProperty()));
我如何设置它以便我可以沿着矩形的边缘移动锚点?
答案 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;
}