【问题标题】:JavaFX: Task will not update UIJavaFX:任务不会更新 UI
【发布时间】:2014-04-22 02:18:37
【问题描述】:

我正在开发一个用 javaFX+java 编写的 Omaha 在线扑克客户端。

control.call() 执行完毕后,我需要显示一个包含 3 个按钮的 anchorPane。 我知道 control.call() 执行完毕,但由于某种原因task.setOnSucceeded(new EventHandler() { 的句柄方法没有更新用户界面。

我做错了什么?

public void newRound() {

    sog = StateOfGame.PREFLOP;       

     ControlGameOnNewThread control = new ControlGameOnNewThread();

    Task task = new Task() {

        @Override
        protected Object call() throws Exception {
            control.call();
            return null;
        }
    };

    task.setOnSucceeded(new EventHandler() {

        @Override
        public void handle(Event event) {
            if (client.getAction() == FirstToAct.me) {
                System.out.println("Task finsished");
                    showOptions(client.getToCall());
                    opponentBetField.setText(new Integer(opp.chipsInvested).toString());
                    myBetField.setText(new Integer(client.chipsInvested).toString());
                    System.out.println("Task finsished");

            }
    }
    });


    new Thread(task).start();


}

【问题讨论】:

  • 你确定你的call(...) 方法是成功的,而不是抛出一个异常?尝试用task.getException().printStackTrace() 注册setOnFailed(...) 处理程序,看看是否有东西被抛出。

标签: java multithreading concurrency javafx task


【解决方案1】:

问题是您正在另一个线程中更新用户界面。如果您在另一个线程中并且想要更新用户界面

你需要调用


Platform.runLater(new Runnable() {
  @Override public void run() {
    //Update UI here     
  }
});

调用它会调用主线程并更新所有必要的用户界面更新

编辑

public void newRound() {

    sog = StateOfGame.PREFLOP;       

     ControlGameOnNewThread control = new ControlGameOnNewThread();

    Task task = new Task() {

        @Override
        protected Object call() throws Exception {
            control.call();
            return null;
        }
    };

    task.setOnSucceeded(new EventHandler() {

        @Override
        public void handle(Event event) {

            if (client.getAction() == FirstToAct.me) {

                Platform.runLater(new Runnable() {
                  @Override public void run() {
                    System.out.println("Task finsished");
                    showOptions(client.getToCall());
                    opponentBetField.setText(new Integer(opp.chipsInvested).toString());
                    myBetField.setText(new Integer(client.chipsInvested).toString());
                    System.out.println("Task finsished");     
                  }
                });
            }
    }
    });


    new Thread(task).start();


}

【讨论】:

  • 我已经尝试实现你所说的,但我遇到了同样的问题。这是新代码:pastebin.com/zcvybKik
  • @zeroRooter 更新了我的答案。我的意思是只更新用户界面而不是类实例
  • 感谢您到目前为止的帮助,但在实施您的解决方案后 UI 仍未更新,我一直认为 Platform.runLater() 无论如何创建了一个新线程。无论如何,这里是整个文档的链接github.com/zeroRooter/Omaha-Poker/blob/master/src/huclient/…(函数 newRound 在第 310 行)
  • @zeroRooter 新的 Thread(task).start(); 在哪里?你把它放在那里了吗?
  • 是的,实际上我似乎忘记了它,但是问题仍然存在,我已经推送了 git。
【解决方案2】:

当您覆盖call() 方法时,您可以覆盖succeeded() 方法:(参见Task 的javadoc 中的最后一个示例。)

@Override protected void succeeded() {
     super.succeeded();
     updateMessage("Done!");
}

succeeded() 已在 JavaFX 应用程序线程上调用,因此您无需自己执行此操作。

您确定没有调用您的句柄方法中的代码吗?也许会抛出 NullPointerException,您可能看不到?比较是否按预期进行?

尝试将带有if (client.getAction()... 的代码移动到覆盖的succeeded() 方法中,并在if 语句之前放置一个println 以查看它是否被调用。

(编辑:错别字)

【讨论】:

  • 第 347 行 ish github.com/zeroRooter/Omaha-Poker/blob/master/src/huclient/… 是的,代码肯定没有被执行,我已经用 println 完成了你所说的,我已经再次将它上传到 git。覆盖成功应该和我正在做的事情一样吗?
  • @zeroRooter 是的 - 将 if 语句及其块放入覆盖的 succeeded() 方法中。它应该做同样的事情。当您使用它时,还要覆盖 failed() 和 cancelled() 并将 println 语句也放在那里。您还应该在 call() 方法中的 return 语句之前放置一个 print 语句。因此,您可以查看调用方法是否成功或在两者之间获得异常。异常将存储在 exceptionProperty 中,您可以在 failed() 方法中查看。
【解决方案3】:

您的信息很有帮助,但我认为建议的所有方法都会奏效(包括我最初的方法)。问题是任务从未结束,这就是 onTaskSucceded 从未执行的原因。为了让任务完成后退出,我必须将守护进程设置为 true:

Thread thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();

【讨论】:

  • 即使这可行,我认为它可能隐藏了一些与您如何使用任务有关的潜在问题。一个任务onTaskSucceeded是否被调用真的不应该和线程的守护进程状态有关。
  • 插入setDaemon(true)的调用后你的“成功”代码是否被执行?
  • 是的,但我认为如果您仍然在不同线程上保留更新 UI 的代码,它也会变得有点混乱。实际上,您需要将 Deamon 设置为 true 并删除所有其他非主 javaFX 线程上更新 UI 的代码。
  • 正如jewelsea 提到的,如果setDaemon(true) “工作”,还有另一个隐藏问题。您需要注意只更新 JavaFX 应用程序线程上的 UI。你应该仔细检查你的代码是否在错误的线程中访问 UI。
猜你喜欢
  • 1970-01-01
  • 2020-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-09
  • 2014-08-26
  • 1970-01-01
相关资源
最近更新 更多