【发布时间】:2022-01-05 18:02:49
【问题描述】:
我目前正在开发一个小型 JavaFX 库来显示 svg 内容。我正在实现动画。它们工作正常,除了 x 和 y 位置的 animate 或 animateTransform,我不明白为什么。
当我这样做时,它完美无缺:
public class TimelineTest extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
Group root = new Group();
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
Rectangle rect = new Rectangle(100, 100, 50, 50);
root.getChildren().add(rect);
rect.setFill(Color.BLUE);
Timeline timeline = new Timeline();
KeyFrame kf0 = new KeyFrame(Duration.ZERO, new KeyValue(rect.xProperty(), 0));
KeyFrame kf1 = new KeyFrame(Duration.seconds(10), new KeyValue(rect.xProperty(), 100));
timeline.getKeyFrames().addAll(kf0, kf1);
timeline.play();
primaryStage.show();
}
}
但是当我在我的库中做我认为完全一样的事情时,矩形似乎有点抽搐但并没有真正移动。
我的代码是:
WritableValue value = null;
switch (nodeName) {
case "rect":
Rectangle rect = (Rectangle) node;
switch (attrName) {
case X:
value = rect.xProperty();
break;
case Y:
value = rect.yProperty();
break;
case WIDTH:
value = rect.widthProperty();
break;
case HEIGHT:
value = rect.heightProperty();
break;
}
break;
}
Timeline timeline = new Timeline();
KeyValue fromValue = new KeyValue(value, 10);
KeyValue toValue = new KeyValue(value, 100);
KeyFrame fromFrame = new KeyFrame(Duration.ZERO, fromValue);
KeyFrame toFrame = new KeyFrame(Duration.seconds(10), toValue);
timeline.getKeyFrames().addAll(fromFrame, toFrame);
奇怪的是,当我对 width 或 height 属性做同样的事情时,它没有任何问题。
我怀疑我的场景没有正确创建(我检查了我是否在平台线程中执行所有这些操作),但其他一切都正常工作。
如果我尝试改用 TranslateTransition,我会遇到完全相同的问题。
在这里对这个问题进行了一些 cmets 之后,我现在不明白为什么我会遇到这个问题(但不知道如何解决它,至少现在是这样)。我将 JavaFX 内容放在 ScrollPane 中。我不认为它在这种情况下是相关的,但它是相关的。代码是:
VBox vBox = new VBox(node);
vBox.setAlignment(Pos.CENTER);
Group group = new Group(vBox );
StackPane content = new StackPane(group);
group.layoutBoundsProperty().addListener((observable, oldBounds, newBounds) -> {
content.setMinWidth(newBounds.getWidth());
content.setMinHeight(newBounds.getHeight());
});
ScrollPane scrollPane = new ScrollPane(content);
scrollPane.setPannable(true);
scrollPane.setFitToHeight(true);
scrollPane.setFitToWidth(true);
scrollPane.setPrefSize(500, 500);
我对 ScrollPane 使用了以下 StackOverflow 答案:JAVAFX zoom, scroll in ScrollPane
这是一个展示所有内容的可复制示例:
public class TestAnimationInScroll extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
Rectangle rect = new Rectangle(100, 100, 50, 50);
rect.setFill(Color.BLUE);
Group root = new Group();
root.getChildren().add(rect);
VBox vBox = new VBox(root);
vBox.setAlignment(Pos.CENTER);
Group group = new Group(root);
StackPane content = new StackPane(group);
group.layoutBoundsProperty().addListener((observable, oldBounds, newBounds) -> {
content.setMinWidth(newBounds.getWidth());
content.setMinHeight(newBounds.getHeight());
});
ScrollPane scrollPane = new ScrollPane(content);
scrollPane.setPannable(true);
scrollPane.setFitToHeight(true);
scrollPane.setFitToWidth(true);
scrollPane.setPrefSize(500, 500);
Timeline timeline = new Timeline();
KeyFrame kf0 = new KeyFrame(Duration.ZERO, new KeyValue(rect.xProperty(), 0));
KeyFrame kf1 = new KeyFrame(Duration.seconds(10), new KeyValue(rect.xProperty(), 100));
timeline.getKeyFrames().addAll(kf0, kf1);
timeline.play();
content.setOnScroll(new EventHandler<ScrollEvent>() {
public void handle(ScrollEvent event) {
double zoomFactor = 1.05;
double deltaY = event.getDeltaY();
if (deltaY < 0) {
zoomFactor = 1 / zoomFactor;
}
Bounds groupBounds = group.getBoundsInLocal();
final Bounds viewportBounds = scrollPane.getViewportBounds();
double valX = scrollPane.getHvalue() * (groupBounds.getWidth() - viewportBounds.getWidth());
double valY = scrollPane.getVvalue() * (groupBounds.getHeight() - viewportBounds.getHeight());
group.setScaleX(group.getScaleX() * zoomFactor);
group.setScaleY(group.getScaleY() * zoomFactor);
Point2D posInZoomTarget = group.parentToLocal(new Point2D(event.getX(), event.getY()));
Point2D adjustment = group.getLocalToParentTransform().deltaTransform(posInZoomTarget.multiply(zoomFactor - 1));
scrollPane.layout();
scrollPane.setViewportBounds(groupBounds);
groupBounds = group.getBoundsInLocal();
scrollPane.setHvalue((valX + adjustment.getX()) / (groupBounds.getWidth() - viewportBounds.getWidth()));
scrollPane.setVvalue((valY + adjustment.getY()) / (groupBounds.getHeight() - viewportBounds.getHeight()));
}
});
Scene scene = new Scene(scrollPane, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
}
可以看到,ScrollPane可以放大,但是看不到动画效果。
如果我在相同的上下文中使用 ScaleTransition,它可以工作,例如:
public class TestAnimationInScroll extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
Rectangle rect = new Rectangle(100, 100, 50, 50);
rect.setFill(Color.BLUE);
Group root = new Group();
root.getChildren().add(rect);
VBox vBox = new VBox(root);
vBox.setAlignment(Pos.CENTER);
Group group = new Group(root);
StackPane content = new StackPane(group);
group.layoutBoundsProperty().addListener((observable, oldBounds, newBounds) -> {
content.setMinWidth(newBounds.getWidth());
content.setMinHeight(newBounds.getHeight());
});
ScrollPane scrollPane = new ScrollPane(content);
scrollPane.setPannable(true);
scrollPane.setFitToHeight(true);
scrollPane.setFitToWidth(true);
scrollPane.setPrefSize(500, 500);
ScaleTransition transition = new ScaleTransition(Duration.seconds(5), rect);
transition.setFromX(1d);
transition.setFromY(1d);
transition.setToX(3d);
transition.setToY(3d);
transition.play();
content.setOnScroll(new EventHandler<ScrollEvent>() {
public void handle(ScrollEvent event) {
double zoomFactor = 1.05;
double deltaY = event.getDeltaY();
if (deltaY < 0) {
zoomFactor = 1 / zoomFactor;
}
Bounds groupBounds = group.getBoundsInLocal();
final Bounds viewportBounds = scrollPane.getViewportBounds();
double valX = scrollPane.getHvalue() * (groupBounds.getWidth() - viewportBounds.getWidth());
double valY = scrollPane.getVvalue() * (groupBounds.getHeight() - viewportBounds.getHeight());
group.setScaleX(group.getScaleX() * zoomFactor);
group.setScaleY(group.getScaleY() * zoomFactor);
Point2D posInZoomTarget = group.parentToLocal(new Point2D(event.getX(), event.getY()));
Point2D adjustment = group.getLocalToParentTransform().deltaTransform(posInZoomTarget.multiply(zoomFactor - 1));
scrollPane.layout();
scrollPane.setViewportBounds(groupBounds);
groupBounds = group.getBoundsInLocal();
scrollPane.setHvalue((valX + adjustment.getX()) / (groupBounds.getWidth() - viewportBounds.getWidth()));
scrollPane.setVvalue((valY + adjustment.getY()) / (groupBounds.getHeight() - viewportBounds.getHeight()));
}
});
Scene scene = new Scene(scrollPane, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
}
有人知道我的错误在哪里吗?也许有一种方法可以在 scrollPane 中进行平移和缩放,但仍然可以正确看到动画?
【问题讨论】:
-
您的代码对我来说运行良好。 Java 8.
-
minimal reproducible example 请(不工作的:)
-
我添加了一个可复制的例子