使用StackPane对象的绝对坐标创建路径转换

编程入门 行业动态 更新时间:2024-10-15 16:24:11
本文介绍了使用StackPane对象的绝对坐标创建路径转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

OrangeBlock 是一个带有文本的橙色块。它实现为 StackPane ,其中包含矩形顶部的文本。 (这种方法在 StackPane的文档中进行了演示。)

OrangeBlock is an orange block with text inside. It is implemented as a StackPane that contains text on top of a rectangle. (This approach is demonstrated in the documentation for StackPane.)

我在坐标(100,80)处放置了 OrangeBlock 试图让它平稳地移动到一些目标坐标。不幸的是,我在路上遇到了一个令人讨厌的问题:

I've placed an OrangeBlock at coordinates (100, 80) and am now trying to make it travel smoothly to some target coordinates. Unfortunately I get a nasty bump in my path:

由于某种原因, PathElement 中的坐标是相对于橙色块解释的。

For some reason the coordinates in the PathElements are interpreted relative to the orange block.

这是为什么?如何让我的 OrangeBlock 沿着绝对坐标的路径行进?下面的最小工作示例。

Why is this? And how can I make my OrangeBlock travel along a path with absolute coordinates? Minimal working example below.

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代码。似乎你运气不好找到合适的解决方案。以下是发生的情况:

I debugged the JavaFX code out of curiosity. Seems like you are out of luck with a proper solution. Here's what happens:

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

The PathTransition code has a method interpolate(double frac) which includes:

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

impl_getPivotX()和impl_getPivotY()方法包含:

The impl_getPivotX() and impl_getPivotY() methods contain this:

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。一个Rectangle节点。此外,您需要layoutBounds,因此必须在边界可用后创建PathTransition。

So the PathTransition always uses the center of your node for the calculation. In other words this works with e. g. a Circle node, but not with e. g. a Rectangle node. Moreover you need the layoutBounds, so the PathTransition must be created after the bounds were made available.

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

You can see in the PathTransition code that the calculations are all relative and already involve the layout position. So in your lineTo you have to consider this.

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

Worth noting is that the LineTo class has a method setAbsolut(boolean). However it doesn't solve your problem.

所以我的问题解决方案是

So my solution to your problem would be

  • 在主要阶段可见后创建PathTransition
  • 修改moveTo和lineTo参数

这对我有用(我添加了一个Rectangle形状来直观地识别正确的边界):

This works for me (I added a Rectangle shape to identify the proper bounds visually):

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:

edit: another solution would be to use this instead of MoveTo and 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。

Note: You still have to create the PathTransition after the primaryStage was created.

编辑:这是块移动到鼠标点击位置的另一个例子:

edit: here's another example with the block moving to the position of the mouse-click:

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); } } }

更多推荐

使用StackPane对象的绝对坐标创建路径转换

本文发布于:2023-11-24 12:44:56,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1625252.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:坐标   路径   对象   StackPane

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!