首页 > 解决方案 > JavaFX在for循环中将节点添加到锚窗格,但每次迭代等待几秒钟,然后再添加下一个节点

问题描述

我正在制作一个游戏,应该发生的是,在一个 for 循环中,同时迭代一个数组列表。在每个循环中,我想将一个节点添加到我的场景中,然后我想等待一段时间并将另一个节点添加到场景中。每次迭代之间的时间也在arraylist的项目中定义,并且每次迭代可以不同。

我试过的:

    //Circle is my own class, other than these attributes along with getters it has nothing in it.
    //The last number is the time to wait.
    //Also for testing i used a static arraylist, normally the items come from a json file.
    ArrayList<Circle> lvlNodes = new ArrayList<>();
    lvlNodes.add(new Circle(50,50, Color.RED,250,100));
    lvlNodes.add(new Circle(200,100, Color.BLUE,500,250));
    lvlNodes.add(new Circle(900,500, Color.YELLOW,750,500));
    lvlNodes.add(new Circle(400,50, Color.GREEN,1000,500));

   //Iterating over the arraylist and adding the nodes.
   for (int i=0; i<lvlNodes.size(); i++) {
        Circle currentNode = lvlNodes.get(i);

        //Add the node the the anchor pane.
        view.addLvlNode(currentNode, diameter); //diameter is a final value, all nodes in the game are the same and thus only added once at the top of the json file

        //Wait and move on to the next one.
        try {
           Thread.sleep(currentNode.getTimeToNextNode())
        } catch (InterruptedException e) {
            System.out.println(e);
        }
        
    }



  //Adds the next node to the game.
  public void addLvlNode(Circle circle, double diameter) {
    //Create node.
    javafx.scene.shape.Circle lvlNode = new javafx.scene.shape.Circle(circle.getPosX(), 
          circle.getPosY(), diameter/2);

    //Anchor node the the anchorpane.
    AnchorPane.setTopAnchor(lvlNode, (double)circle.getPosY());
    AnchorPane.setLeftAnchor(lvlNode, (double)circle.getPosX());
    anchrLevel.getChildren().add(lvlNode);
    lvlNode.toBack();
  }//addLvlNode.

Thread.sleep() 有效,for 循环中的每次迭代都包含中间的时间。但是在 for 循环完成迭代之前不会添加节点。

有没有办法在 for 循环中添加节点,中间有时间量?

标签: javajavafx

解决方案


您遇到的问题是您的所有代码都在 FXAT 上运行,而当 FXAT 忙于运行该代码时,它无法执行更新屏幕以实际添加圆圈等操作。因此,当您的代码完成时,包括所有 Thread.sleep() 调用,它会同时完成所有屏幕绘制。

我没有构建您的自定义 Circle 类,而是构建了一些数组来保存 Circles 和等待时间。然后我将 addLvlNode & sleep 放入后台作业。后台作业使用 Platform.runLater() 将节点添加到 FXAT 的窗格中:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

import java.util.ArrayList;

public class CircleMaker extends Application {

    private Pane mainPain;

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

    @Override
    public void start(Stage primaryStage) {
        ArrayList<Circle> circles = new ArrayList<>();
        ArrayList<Integer> waitTimes = new ArrayList<>();
        circles.add(new Circle(50, 50, 125, Color.RED));
        waitTimes.add(1000);
        circles.add(new Circle(200, 200, 250, Color.BLUE));
        waitTimes.add(2500);
        circles.add(new Circle(900, 500, 375, Color.YELLOW));
        waitTimes.add(5000);
        circles.add(new Circle(400, 50, 500, Color.GREEN));
        waitTimes.add(5000);
        Thread waitingThread = new Thread(() -> {
            for (int idx = 0; idx < 4; idx++) {
                Circle thisCircle = circles.get(idx);
                Platform.runLater(() -> addLvlNode(thisCircle));
                try {
                    Thread.sleep(waitTimes.get(idx));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        mainPain = new Pane();
        primaryStage.setScene(new Scene(mainPain, 1000, 800));
        primaryStage.show();
        waitingThread.start();
    }

    private void addLvlNode(Node circle) {
        mainPain.getChildren().add(circle);
        circle.toBack();
    }

}

我还将等待时间延长了 10 倍,以便更容易看到每个圆圈都是轮流绘制的,它们之间有一个暂停。

您可能可以使用 Timeline 来执行此操作,但是由于您说 Circle 数据最终将是来自外部源的 JSON,这对我来说意味着您可能已经发生了某种非 JavaFX 机制,所以这可能是最好的只使用后台线程来做你需要的任何事情。您可以从这个示例中看到基本框架是什么。


推荐阅读