JavaFX显示新标签然后休眠循环的每次迭代

时间:2017-05-20 22:16:16

标签: java multithreading javafx

我正在为我的Java课程中的最终项目创建一个黑色插孔程序,我想模拟经销商在一轮结束时给自己的卡片。我想睡一个while循环的每次迭代1秒钟以显示轻微的暂停。以下是基于我在堆栈溢出时读过的不同线程的两次尝试,但都不起作用。

Timeline timeline = new Timeline(
        new KeyFrame(Duration.millis(1000), event ->
        {
            if(dealer.getScore() < 17 || (dealer.getScore() < player.getScore() && dealer.getScore() <= 21))
            {
                newCard(dealer, mainDeck.deal(), false);
                System.out.println("Running Here!");
                LBLDeck.setText(String.valueOf(mainDeck.getRemaingCards()) + " cards remaining");
            }
        })
);
timeline.setCycleCount(1);
System.out.println("Starting loop!");

和这一个:

while (dealer.getScore() < 17 || (dealer.getScore() < player.getScore() && dealer.getScore() <= 21))
{
    new Thread(() ->
    {
        try
        {
            Thread.sleep(1000);
            newCard(dealer, mainDeck.deal(), false);
            LBLDeck.setText(String.valueOf(mainDeck.getRemaingCards()) + " cards remaining");
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }).run();
}

我不太确定第一个例子有什么问题,因为我之前从未使用过时间轴。至于第二个,它似乎计算睡眠时间的总量并冻结我的程序持续时间。 I.E.如果循环进行了3次我的程序睡眠3秒然后继续。然后它立即吐出所有标签。

1 个答案:

答案 0 :(得分:1)

您的时间轴只执行一次,因为它只有一个KeyFrame,并且您将周期数设置为1(因此整个时间轴只执行一次)。

您可以将周期数设置为INDEFINITE(因此会永久重复)并在满足条件时明确停止时间线:

Timeline timeline = new Timeline();
KeyFrame keyFrame = new KeyFrame(Duration.millis(1000), event -> {

    if(dealer.getScore() >= 17 && (dealer.getScore() >= player.getScore() || dealer.getScore() > 21)) {
        timeline.stop();
    } else {
        newCard(dealer, mainDeck.deal(), false);
        System.out.println("Running Here!");
        LBLDeck.setText(String.valueOf(mainDeck.getRemaingCards()) + " cards remaining");
    }
});

timeline.getKeyFrames().add(keyFrame);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();

您的线程解决方案有几个问题。首先,你根本没有在后台线程上运行线程的runnable:Thread.run()只是在当前线程上执行runnable,这是FX Application Thread。因此,您的Thread.sleep()会阻止FX应用程序线程,从而导致UI无法呈现并且无法响应。要实际启动新主题,请改为调用Thread.start()

第二个问题是您调用的newCard()setText()方法会更改UI,而后台线程无法做到这一点。您需要在FX应用程序线程上执行这些操作:您可以将它们包装在Platform.runLater(...)

最后,您正在为您处理的每张卡创建一个新线程,并且(一旦修复),启动该线程。因此,每张卡片将基本上同时处理,每个线程一张。这不是你想要的:你想要一个后台线程一次处理一张牌并在每张牌之间暂停。因此,创建一个后台线程并在其中运行整个循环:

new Thread(() -> {
    while (dealer.getScore() < 17 || (dealer.getScore() < player.getScore() && dealer.getScore() <= 21)) {
        try {
            Thread.sleep(1000);
            newCard(dealer, mainDeck.deal(), false);
            LBLDeck.setText(String.valueOf(mainDeck.getRemaingCards()) + " cards remaining");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}).start();