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

标签 java multithreading javafx

我正在为 Java 类(class)的最后一个项目创建一个黑 jack 程序,我想模拟荷官在一轮结束时给自己发牌。我想让 while 循环的每次迭代 hibernate 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();
}

我不太确定第一个示例有什么问题,因为我以前从未使用过时间线。至于第二个,它似乎计算了总 sleep 时间并在该持续时间内卡住我的程序。 IE。如果循环进行 3 次,我的程序会 hibernate 3 秒,然后继续。然后它立即吐出所有标签。

最佳答案

您的时间轴仅执行一次,因为它只有一个 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();

您的线程解决方案有几个问题。首先,您根本没有在后台线程上运行线程的可运行对象:Thread.run() 只是在当前线程(即 FX 应用程序线程)上执行可运行对象。因此,您的 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();

关于JavaFX 显示新标签然后 hibernate 循环的每次迭代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44091316/

相关文章:

java - 更改 InlineCSSTextArea javafX 中突出显示文本的字体/大小/颜色/格式

listview - 如何通过鼠标拖动在 JavaFX ListView 中选择多行

java - Avro 中 DatumWriter 的用途是什么

java - 如何从线程取回数组值

C# 并发列表访问

java - DataFormatException : incorrect header check in java. util.zip.InflaterInputStream

java - 使用Java,需要通过代理建立https连接

java - 具有可变数量的构造函数参数的子类的静态工厂方法

java - 以编程方式启用通知 channel

Windows SuspendThread 没有? (GetThreadContext 失败)