使用LineTo、MoveTo将按钮移动到JavaFX中的指定坐标,并使用路径转换



我正在制作一个动画,其中涉及移动表示在网络中传输的数据的按钮。到目前为止,我已经能够通过更新按钮的LayoutX和LayoutY字段,以及使用顺序转换,在动画的不同阶段将按钮移动到不同的位置。

但现在我正试图让这个名为蓝色的按钮沿着对角线从它在舞台上的位置移动到"路由器3",它在按钮的右边。目的地的确切布局坐标为426(x)和364(y),起始位置的布局坐标为309(x)或585(y)。我一直在尝试将moveTo与LineTo一起使用,以将按钮移动到上述坐标,但事实证明这很困难,原因有两个:

首先,我使用转换来获得起始坐标,因此按钮到达起始位置时的实际坐标为LayoutX:14、LayoutY:445、TranslateX:295、TranslateY:140。我试着用代码纠正这个问题:

blue.setLayoutX(blue.getLayoutX() + blue.getTranslateX());
blue.setLayoutY(blue.getLayoutY() + blue.getTranslateY());
blue.setTranslateX(0);
blue.setTranslateY(0);

然后将蓝色的路径定义为:

Path path = new Path();
MoveTo start = new MoveTo();
start.setX(blue.getTranslateX());
start.setY(blue.getTranslateY());
path.getElements().add(start);
path.getElements().add(new LineTo(125.0f, -220.0f));
PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(Duration.millis(1000));
pathTransition.setPath(path);
pathTransition.setNode(blue);
pathTransition.setCycleCount((int) 1f);
pathTransition.setAutoReverse(false);
pathTransition.play();

但这似乎是一个繁琐的变通方法。例如,这个程序的下一阶段有按钮,根据Dijkstra的算法遍历多个"路由器"的网络,我希望能够定义一条直接通往下一个路由器的线路路径,而不必在每个阶段都篡改平移和布局坐标。或者,例如,Swing可以在逐像素更新圆坐标的同时重新绘制圆,以便制作对角线动画,并在到达某个位置后停止。使用JavaFX可以做到这一点吗?

其次,即使在动画开始时,按钮似乎也会稍微"向后跳",就好像要行进的路径的起点是按钮实际所在位置的左侧几个像素,尽管据我所知,在动画开始之前,我已经将路径的起点指定为按钮所在的位置。这有什么特别的原因吗?

感谢您对我的问题提供的任何帮助;这是我第一次使用StackOverflow。我很确定我已经彻底地寻找了这类问题的答案,但如果这是重复的,我很抱歉。

这是一个已知的问题,您可以在为StackPane对象线程创建具有绝对坐标的路径转换中了解它。

不幸的是,您必须解决这个问题,JavaFX内部没有解决方案。幸运的是,解决方案很简单,只需使用MoveTo和LineTo的修改版本即可。

下面是一个修改后的示例代码。只需单击场景中的某个位置,节点就会移动到那里而不会"跳跃"。

public class PathTransitionExample extends Application {
PathTransition transition;
@Override
public void start(Stage primaryStage) throws Exception {
Group root = new Group();
// create movable object
Rectangle rect = new Rectangle(50, 50);
rect.setStroke(Color.BLUE);
rect.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.3));
rect.relocate(100, 80);
root.getChildren().add(rect);
Label label = new Label("Click on scene to set destination");
label.relocate(0, 0);
root.getChildren().add(label);
// init transition
transition = new PathTransition();
transition.setNode(rect);
transition.setDuration(Duration.seconds(2));
Scene scene = new Scene(root, 1024, 768);
scene.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<Event>() {
@Override
public void handle(Event event) {
transition.stop();
setPositionFixed( rect);
double toX = ((MouseEvent) event).getX();
double toY = ((MouseEvent) event).getY();
Path path = new Path();
path.getElements().add(new MoveToAbs(rect));
path.getElements().add(new LineToAbs(rect, toX, toY));
transition.setPath(path);
transition.play();
}
// change layout to current position, reset translate
private void setPositionFixed( Node node) {
double x = rect.getLayoutX() + rect.getTranslateX();
double y = rect.getLayoutY() + rect.getTranslateY();
rect.relocate(x, y);
rect.setTranslateX(0);
rect.setTranslateY(0);
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
public static class MoveToAbs extends MoveTo {
public MoveToAbs(Node node) {
super(node.getLayoutBounds().getWidth() / 2, node.getLayoutBounds().getHeight() / 2);
}
public MoveToAbs(Node node, double x, double y) {
super(x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
}
}
public static class LineToAbs extends LineTo {
public LineToAbs(Node node, double x, double y) {
super(x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
}
}
public static void main(String[] args) {
launch(args);
}
}

最新更新