gpt4 book ai didi

javafx - 为 StackPane 对象创建具有绝对坐标的路径过渡

转载 作者:行者123 更新时间:2023-12-04 21:52:08 30 4
gpt4 key购买 nike

OrangeBlock是一个橙色方块,里面有文字。它被实现为 StackPane包含矩形顶部的文本。 (此方法在 the documentation for StackPane 中演示。)

我已经放置了一个 OrangeBlock在坐标 (100, 80) 处,现在正试图让它平稳地移动到某个目标坐标。不幸的是,我在我的道路上遇到了令人讨厌的颠簸:

Bumpy PathTransition

出于某种原因,PathElement 中的坐标s 相对于橙色块进行解释。

为什么是这样?以及如何制作我的 OrangeBlock沿着具有绝对坐标的路径旅行?下面的最小工作示例。

import javafx.animation.PathTransition;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.util.Duration;

public class PathTransitionExample extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Group root = new Group();

OrangeBlock block = new OrangeBlock(60, 40);
block.relocate(100, 80);
root.getChildren().add(block);

PathTransition transition = newPathTransitionTo(block, 460, 320);

primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
transition.play();
}

private static PathTransition newPathTransitionTo(OrangeBlock block,
double toX, double toY) {
double fromX = block.getLayoutX();
double fromY = block.getLayoutY();

Path path = new Path();
path.getElements().add(new MoveTo(fromX, fromY));
path.getElements().add(new LineTo(toX, toY));

PathTransition transition = new PathTransition();
transition.setPath(path);
transition.setNode(block);
transition.setDelay(Duration.seconds(1));
transition.setDuration(Duration.seconds(2));

return transition;
}

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

private static class OrangeBlock extends StackPane {
public OrangeBlock(int width, int height) {
Rectangle rectangle = new Rectangle(width, height, Color.ORANGE);
Text text = new Text("Block");
getChildren().addAll(rectangle, text);
}
}
}

最佳答案

出于好奇,我调试了 JavaFX 代码。似乎您对正确的解决方案不走运。这是发生的事情:

PathTransition 代码有一个方法 interpolate(double frac) ,其中包括:

cachedNode.setTranslateX(x - cachedNode.impl_getPivotX());
cachedNode.setTranslateY(y - cachedNode.impl_getPivotY());

impl_getPivotX() 和 impl_getPivotY() 方法包含以下内容:
public final double impl_getPivotX() {
final Bounds bounds = getLayoutBounds();
return bounds.getMinX() + bounds.getWidth()/2;
}

public final double impl_getPivotY() {
final Bounds bounds = getLayoutBounds();
return bounds.getMinY() + bounds.getHeight()/2;
}

因此 PathTransition 始终使用节点的中心进行计算。换句话说,这适用于 e。 G。一个 Circle 节点,但不带 e。 G。一个矩形节点。此外,您需要 layoutBounds,因此必须在边界可用后创建 PathTransition。

可以在PathTransition代码中看到,计算都是相对的,已经涉及到布局位置了。所以在你的行中你必须考虑这一点。

值得注意的是 LineTo 类有一个方法 setAbsolut(boolean)。然而它并不能解决你的问题。

所以我对你的问题的解决方案是
  • 在初级阶段可见后创建 PathTransition
  • 修改 moveTo 和 lineTo 参数

  • 这对我有用(我添加了一个 Rectangle 形状来直观地识别正确的边界):
    public class PathTransitionExampleWorking2 extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {

    Group root = new Group();

    Rectangle rect = new Rectangle( 100, 80, 460-100+60, 320-80+40);
    root.getChildren().add(rect);

    OrangeBlock block = new OrangeBlock(60, 40);
    block.relocate( 100, 80);

    root.getChildren().add(block);

    primaryStage.setScene(new Scene(root, 600, 400));
    primaryStage.show();

    // layout bounds are used in path transition => PathTransition creation must happen when they are available
    PathTransition transition = newPathTransitionTo(block, 460, 320);
    transition.play();
    }

    private static PathTransition newPathTransitionTo(OrangeBlock block, double toX, double toY) {

    double fromX = block.getLayoutBounds().getWidth() / 2;
    double fromY = block.getLayoutBounds().getHeight() / 2;

    toX -= block.getLayoutX() - block.getLayoutBounds().getWidth() / 2;
    toY -= block.getLayoutY() - block.getLayoutBounds().getHeight() / 2;

    Path path = new Path();
    path.getElements().add(new MoveTo(fromX, fromY));
    path.getElements().add(new LineTo(toX, toY));

    PathTransition transition = new PathTransition();
    transition.setPath(path);
    transition.setNode(block);
    transition.setDelay(Duration.seconds(1));
    transition.setDuration(Duration.seconds(2));

    return transition;
    }

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

    private static class OrangeBlock extends StackPane {
    public OrangeBlock(int width, int height) {
    Rectangle rectangle = new Rectangle(width, height, Color.ORANGE);
    Text text = new Text("Block");
    getChildren().addAll(rectangle, text);
    }
    }
    }

    编辑:另一种解决方案是使用它而不是 MoveTo 和 LineTo:
    public static class MoveToAbs extends MoveTo {

    public MoveToAbs( Node node) {
    super( node.getLayoutBounds().getWidth() / 2, 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);
    }

    }

    注意:在创建primaryStage 之后,您仍然需要创建PathTransition。

    编辑:这是块移动到鼠标单击位置的另一个示例:
    public class PathTransitionExample extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {

    Group root = new Group();

    OrangeBlock block = new OrangeBlock(60, 40);
    block.relocate(100, 80);
    root.getChildren().add(block);

    Label label = new Label( "Click on scene to set destination");
    label.relocate(0, 0);
    root.getChildren().add(label);

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

    scene.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler<Event>() {

    PathTransition transition;

    {
    transition = new PathTransition();
    transition.setNode(block);
    transition.setDuration(Duration.seconds(2));

    }

    @Override
    public void handle(Event event) {

    transition.stop();

    setPositionFixed(block.getLayoutX() + block.getTranslateX(), block.getLayoutY() + block.getTranslateY());

    double x = ((MouseEvent) event).getX();
    double y = ((MouseEvent) event).getY();

    Path path = new Path();
    path.getElements().add(new MoveToAbs( block));
    path.getElements().add(new LineToAbs( block, x, y));

    transition.setPath(path);
    transition.play();

    }

    private void setPositionFixed( double x, double y) {
    block.relocate(x, y);
    block.setTranslateX(0);
    block.setTranslateY(0);
    }

    });

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

    PathTransition transition = newPathTransitionTo(block, 460, 320);
    transition.play();

    }

    private static PathTransition newPathTransitionTo(OrangeBlock block, double toX, double toY) {

    Path path = new Path();
    path.getElements().add(new MoveToAbs( block));
    path.getElements().add(new LineToAbs( block, toX, toY));

    PathTransition transition = new PathTransition();
    transition.setPath(path);
    transition.setNode(block);
    transition.setDelay(Duration.seconds(1));
    transition.setDuration(Duration.seconds(2));

    return transition;
    }

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

    private static class OrangeBlock extends StackPane {
    public OrangeBlock(int width, int height) {
    Rectangle rectangle = new Rectangle(width, height, Color.ORANGE);
    Text text = new Text("Block");
    getChildren().addAll(rectangle, text);
    }
    }

    public static class MoveToAbs extends MoveTo {

    public MoveToAbs( Node node) {
    super( node.getLayoutBounds().getWidth() / 2, 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);
    }

    }
    }

    关于javafx - 为 StackPane 对象创建具有绝对坐标的路径过渡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27659474/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com