老虎机 TimeLine 动画不工作
Slot machine TimeLine animation not working
我正在尝试开发老虎机卷轴应用程序。我有一个自定义卷轴窗格,它垂直添加 children。单击旋转按钮时,child 人必须移动,当最后一个 child 到达边界时,它必须将其位置移到第一个 child 上方。我所做的如下所示。
public class ReelPane extends Pane {
Timeline timeline = new Timeline();
@Override
protected void layoutChildren() {
List<Node> managed = getChildren();
double y = 0;
for (Node node : managed) {
node.setLayoutX(0);
node.setLayoutY(y);
y += node.getBoundsInLocal().getHeight();
}
}
public void spin() {
List<Node> managed = getChildren();
double dy = 4;
for (Node node : managed) {
timeline.getKeyFrames().addAll(new KeyFrame(Duration.millis(2000),new KeyValue(node.layoutYProperty(),node.getLayoutY()+dy)));
if(node.getLayoutY()>=600){
node.setLayoutY(-50);
}
}
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
}
}
fxml 文件
<?import javafx.scene.control.Button?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.Pane?>
<?import sample.ReelPane?>
<Pane stylesheets="@css/slot.css"
xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx"
fx:controller="sample.Controller">
<ReelPane fx:id="reel" styleClass="container">
<ImageView fitHeight="100" fitWidth="100">
<Image url="/sample/resources/apple.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100">
<Image url="/sample/resources/diamond.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100">
<Image url="/sample/resources/glass.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100">
<Image url="/sample/resources/grape.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100">
<Image url="/sample/resources/star.png"/>
</ImageView>
</ReelPane>
<Button fx:id="spin" text="SPIN"/>
</Pane>
控制器
package sample;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class Controller {
@FXML
ReelPane reel;
@FXML
Button spin;
public void initialize() {
spin.setOnAction(event -> reel.spin());
}
}
主要
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Parent root =
FXMLLoader.load(getClass().getResource("resources/fxml/slot.fxml"));
primaryStage.setScene(new Scene(root, 400, 900));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
但是 children 在按钮按下时没有移动 clicked.Can 有人告诉我哪里出了问题吗?
您 Timeline
的所有 KeyFrame
都同时安排。此外,if
语句甚至在您开始动画之前就已执行。
恕我直言,将所有元素放在 VBox
中并简单地反复将 translateY
从等于元素高度的负值更改为 0 并将最后一个元素移到前面循环结束。您可能希望将 clip
应用于 VBox
的父级,但要隐藏任何超出单个元素边界的内容。
@Override
public void start(Stage primaryStage) throws Exception {
VBox pane = new VBox();
Pane parent = new Pane(pane);
parent.setPrefSize(50, 50);
parent.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
parent.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
Timeline timeline = new Timeline(new KeyFrame(Duration.ZERO, new KeyValue(pane.translateYProperty(), -50d)),
new KeyFrame(Duration.seconds(2), evt -> {
pane.getChildren().get(pane.getChildren().size() - 1).toBack();
}, new KeyValue(pane.translateYProperty(), 0d)));
timeline.setCycleCount(Animation.INDEFINITE);
for (int i = 0; i < 6; i++) {
Rectangle rect = new Rectangle(50, 50, Color.RED.interpolate(Color.BLACK, i / 6d));
pane.getChildren().add(rect);
}
parent.setClip(new Rectangle(50, 50));
timeline.play();
Scene scene = new Scene(new StackPane(parent), 200, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
制作所需动画的更简单的工具是 PauseTransition
。
如果你不想在 fxml 中指定布局,你可以像你所做的那样覆盖 layoutChildren() 但是 你需要禁用自动布局 (layoutChildren()) 以便动画可以改变职位:
import java.util.List;
import javafx.animation.PauseTransition;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.util.Duration;
public class ReelPane extends Pane {
private List<Node> managed;
private double dy, numberOfCchildren;
private boolean isAnimating = false;
private static final double PAUSE = 1;
@Override
protected void layoutChildren() {
if(isAnimating) return;
managed = getChildren();
numberOfCchildren = managed.size();
double y = 0;
for (Node node : managed) {
node.setLayoutX(0);
node.setLayoutY(y);
dy = Math.max(dy, node.getBoundsInLocal().getHeight()); //dy stores the highest
y += dy;
}
}
public void spin() {
isAnimating = true;
PauseTransition pause = new PauseTransition(Duration.seconds(PAUSE));
pause.setOnFinished(event ->{
for (Node node : managed) {
if(node.getLayoutY()>= (numberOfCchildren -1) * dy){
node.setLayoutY(-dy);
}
node.setLayoutY(node.getLayoutY() +dy);
}
pause.play();
});
pause.play();
}
}
考虑在旋转时禁用按钮:
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class Controller {
@FXML
ReelPane reel;
@FXML
Button spin;
public void initialize() {
spin.setOnAction(event -> {
reel.spin();
spin.setDisable(true);
});
}
}
要使代码 mre 这里是 slot.fxml
使用公开资源:
<?import javafx.scene.control.Button?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.Pane?>
<?import fx_tests.ReelPane?>
<Pane
xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx"
fx:controller="fx_tests.sample.Controller">
<ReelPane fx:id="reel">
<ImageView fitHeight="100" fitWidth="100">
<Image url="https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Box_Green.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100" >
<Image url="https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Box_Red.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100">
<Image url="https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Box_Yellow.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100" >
<Image url="https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Box_Blue.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100">
<Image url="https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Box_Orange.png"/>
</ImageView>
</ReelPane>
<Button fx:id="spin" text="SPIN" layoutX="20." layoutY="550.0" />
</Pane>
测试应用程序:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Parent root =
FXMLLoader.load(getClass().getResource("slot.fxml"));
primaryStage.setScene(new Scene(root, 200, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我正在尝试开发老虎机卷轴应用程序。我有一个自定义卷轴窗格,它垂直添加 children。单击旋转按钮时,child 人必须移动,当最后一个 child 到达边界时,它必须将其位置移到第一个 child 上方。我所做的如下所示。
public class ReelPane extends Pane {
Timeline timeline = new Timeline();
@Override
protected void layoutChildren() {
List<Node> managed = getChildren();
double y = 0;
for (Node node : managed) {
node.setLayoutX(0);
node.setLayoutY(y);
y += node.getBoundsInLocal().getHeight();
}
}
public void spin() {
List<Node> managed = getChildren();
double dy = 4;
for (Node node : managed) {
timeline.getKeyFrames().addAll(new KeyFrame(Duration.millis(2000),new KeyValue(node.layoutYProperty(),node.getLayoutY()+dy)));
if(node.getLayoutY()>=600){
node.setLayoutY(-50);
}
}
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.play();
}
}
fxml 文件
<?import javafx.scene.control.Button?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.Pane?>
<?import sample.ReelPane?>
<Pane stylesheets="@css/slot.css"
xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx"
fx:controller="sample.Controller">
<ReelPane fx:id="reel" styleClass="container">
<ImageView fitHeight="100" fitWidth="100">
<Image url="/sample/resources/apple.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100">
<Image url="/sample/resources/diamond.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100">
<Image url="/sample/resources/glass.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100">
<Image url="/sample/resources/grape.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100">
<Image url="/sample/resources/star.png"/>
</ImageView>
</ReelPane>
<Button fx:id="spin" text="SPIN"/>
</Pane>
控制器
package sample;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class Controller {
@FXML
ReelPane reel;
@FXML
Button spin;
public void initialize() {
spin.setOnAction(event -> reel.spin());
}
}
主要
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Parent root =
FXMLLoader.load(getClass().getResource("resources/fxml/slot.fxml"));
primaryStage.setScene(new Scene(root, 400, 900));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
但是 children 在按钮按下时没有移动 clicked.Can 有人告诉我哪里出了问题吗?
您 Timeline
的所有 KeyFrame
都同时安排。此外,if
语句甚至在您开始动画之前就已执行。
恕我直言,将所有元素放在 VBox
中并简单地反复将 translateY
从等于元素高度的负值更改为 0 并将最后一个元素移到前面循环结束。您可能希望将 clip
应用于 VBox
的父级,但要隐藏任何超出单个元素边界的内容。
@Override
public void start(Stage primaryStage) throws Exception {
VBox pane = new VBox();
Pane parent = new Pane(pane);
parent.setPrefSize(50, 50);
parent.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
parent.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
Timeline timeline = new Timeline(new KeyFrame(Duration.ZERO, new KeyValue(pane.translateYProperty(), -50d)),
new KeyFrame(Duration.seconds(2), evt -> {
pane.getChildren().get(pane.getChildren().size() - 1).toBack();
}, new KeyValue(pane.translateYProperty(), 0d)));
timeline.setCycleCount(Animation.INDEFINITE);
for (int i = 0; i < 6; i++) {
Rectangle rect = new Rectangle(50, 50, Color.RED.interpolate(Color.BLACK, i / 6d));
pane.getChildren().add(rect);
}
parent.setClip(new Rectangle(50, 50));
timeline.play();
Scene scene = new Scene(new StackPane(parent), 200, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
制作所需动画的更简单的工具是 PauseTransition
。
如果你不想在 fxml 中指定布局,你可以像你所做的那样覆盖 layoutChildren() 但是 你需要禁用自动布局 (layoutChildren()) 以便动画可以改变职位:
import java.util.List;
import javafx.animation.PauseTransition;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.util.Duration;
public class ReelPane extends Pane {
private List<Node> managed;
private double dy, numberOfCchildren;
private boolean isAnimating = false;
private static final double PAUSE = 1;
@Override
protected void layoutChildren() {
if(isAnimating) return;
managed = getChildren();
numberOfCchildren = managed.size();
double y = 0;
for (Node node : managed) {
node.setLayoutX(0);
node.setLayoutY(y);
dy = Math.max(dy, node.getBoundsInLocal().getHeight()); //dy stores the highest
y += dy;
}
}
public void spin() {
isAnimating = true;
PauseTransition pause = new PauseTransition(Duration.seconds(PAUSE));
pause.setOnFinished(event ->{
for (Node node : managed) {
if(node.getLayoutY()>= (numberOfCchildren -1) * dy){
node.setLayoutY(-dy);
}
node.setLayoutY(node.getLayoutY() +dy);
}
pause.play();
});
pause.play();
}
}
考虑在旋转时禁用按钮:
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class Controller {
@FXML
ReelPane reel;
@FXML
Button spin;
public void initialize() {
spin.setOnAction(event -> {
reel.spin();
spin.setDisable(true);
});
}
}
要使代码 mre 这里是 slot.fxml
使用公开资源:
<?import javafx.scene.control.Button?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.Pane?>
<?import fx_tests.ReelPane?>
<Pane
xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx"
fx:controller="fx_tests.sample.Controller">
<ReelPane fx:id="reel">
<ImageView fitHeight="100" fitWidth="100">
<Image url="https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Box_Green.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100" >
<Image url="https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Box_Red.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100">
<Image url="https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Box_Yellow.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100" >
<Image url="https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Box_Blue.png"/>
</ImageView>
<ImageView fitHeight="100" fitWidth="100">
<Image url="https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Box_Orange.png"/>
</ImageView>
</ReelPane>
<Button fx:id="spin" text="SPIN" layoutX="20." layoutY="550.0" />
</Pane>
测试应用程序:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Parent root =
FXMLLoader.load(getClass().getResource("slot.fxml"));
primaryStage.setScene(new Scene(root, 200, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}