JavaFX SwingWorker 等价物?

Posted

技术标签:

【中文标题】JavaFX SwingWorker 等价物?【英文标题】:JavaFX SwingWorker Equivalent? 【发布时间】:2015-03-06 02:36:18 【问题描述】:

是否有与 Java SwingWorker 类等效的 JavaFX?

我知道 JavaFX Task 但您只能发布字符串消息或进度。我只想在 GUI 线程中调用一个方法,就像我对 SwingWorker 所做的那样(通过发布任意类型的消息)。

这是我的意思的一个例子:

class PrimeNumbersTask extends
         SwingWorker<List<Integer>, Integer> 
     PrimeNumbersTask(JTextArea textArea, int numbersToFind) 
         //initialize
     

      @Override
     public List<Integer> doInBackground() 
         while (! enough && ! isCancelled()) 
                 number = nextPrimeNumber();
                 publish(number);
                 setProgress(100 * numbers.size() / numbersToFind);
             
         
         return numbers;
     

      @Override
     protected void process(List<Integer> chunks) 
         for (int number : chunks) 
             textArea.append(number + "\n"); // HERE: execute in GUI thread
         
     
 

解决方案

非常感谢您的回答。我正在寻找的解决方案是使用Platform.runLater(Runnable guiUpdater)。

【问题讨论】:

【参考方案1】:

我会重写你的SwingWorker 如下:

class PrimeNumbersTask extends Task<List<Integer>> 
    PrimeNumbersTask(TextArea textArea, int numbersToFind) 
        // initialize
    

    @Override
    protected List<Integer> call() throws Exception 
        while (!enough && !isCancelled()) 
            number = nextPrimeNumber();
            updateMessage(Integer.toString(number));
            updateProgress(numbers.size(), numbersToFind);
        
        return numbers;
    

用法:

TextArea textArea = new TextArea();
PrimeNumbersTask task = new PrimeNumbersTask(numbersToFind);
task.messageProperty().addListener((w, o, n)->textArea.appendText(n + "\n"));
new Thread(task).start(); // which would actually start task on a new thread 

说明:

是的,我们没有 publish() 方法,就像 JavaFX 中的 SwingWorker 那样,但在您的情况下,使用 updateMessage() 就足够了,因为我们可以为此属性注册一个侦听器并在每个消息更新的时间。

如果这还不够,您可以随时使用Platform.runLater() 来安排 GUI 更新。如果您进行过多的 GUI 更新并且 GUI 线程被拖慢,您可以使用以下成语:Throttling javafx gui updates

【讨论】:

我已经在考虑这个解决方案,但在我看来它更像是一种解决方法(好吧,它适用于主要示例,但并非在所有情况下都适用)。 Platform.runLater() 方法正是我想要的。 您刚刚创建了新的任务实例,并没有启动 PrimeNumbersTask 的任何后台工作。我想需要调用把它放在一个线程上并启动它。否则,如果只是调用 task.run() GUI 被阻止.. 我随意添加缺少的行: new Thread(task).start();让我知道这是否可以【参考方案2】:

除了只能传递字符串的updateMessage 方法之外,还有可以传递整个对象的updateValue 方法,所以我相信你可以以类似的方式使用它。 Task 文档的“返回部分结果的任务”部分描述了这种方法。另一种方法是其他答案中也提到的Platform.runLater() 方法。

请注意,这些方法之间的一个重要区别是,第一个方法是合并结果,这意味着对于多个频繁的 updateValue 调用,可能会省略一些方法,以防止 FX 线程泛滥。

另一方面,Platform.runLater 方法将发送所有中间结果,但由于如果您有高频更新会导致 FX 线程泛滥的危险,可能需要一些额外的努力来手动避免它,例如 @eckig在他的回答中建议指向Throttling javafx gui updates

【讨论】:

【参考方案3】:

永远不要使用 SwingWorker。 SwingWorker.java 源代码中的这段代码应该足以作为不使用它的参数:

private static final int MAX_WORKER_THREADS = 10;

而是让自己熟悉Executor 以及随之而来的服务。

它与 JavaFX 无关,它只是普通的 Java。但是,您的问题与 JavaFX 有关。这是一个关于如何Update UI in JavaFX Application Thread using Platform.runLater()的示例。

【讨论】:

了解您的不喜欢,但只是想知道SwingWorker 是否实际上没有处理从非 EDT 到 EDT (process) 的块传输,比创建 Runnable 时的效率略高。时间。查看publish 的源代码,我看到AccumulativeRunnable 实例包含在包sun.swing 中。不知道这意味着什么,作为一个完整的 JavaFX 新手,我不知道我们是否会看到类似的东西......

以上是关于JavaFX SwingWorker 等价物?的主要内容,如果未能解决你的问题,请参考以下文章

Linux 上的 JavaFX 显示“图形设备初始化失败:es2,sw”

发布/处理使 SwingWorker 变慢

等待多个 SwingWorker

java - JLabel setForeground 在 SwingWorker 中不起作用

在 swingworker 工作时禁用一切?

如果使用 SwingWorker 加载数据,何时将 TabelModel 绑定到 JTable?