JavaFX多线程 - 加入线程不会更新UI [英] JavaFX multithreading - joining threads won't update the UI

查看:247
本文介绍了JavaFX多线程 - 加入线程不会更新UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个加载程序对话框,用户可以知道程序正在加载所请求的程序以及程序是否按预期运行。

I am trying to make a loader dialog where the user can know that the program is loading what was requested and that the program is running as expected.

但是所以,我需要 join()解析器线程,然后继续使用main,这会使对话框变为空白。

But as so, I need to join() the parser thread and before keep going on the main and this makes the dialog blank.

ParserTask.java

public class ParserTask extends Task<Void>{
    @Override
    protected Void call() throws Exception {
        for(int i=0;i<10;i++){
            //parse stuff
            Thread.sleep(1000);
            updateProgress(i,9);
            updateMessage("foo no:"+ i);
        }
        updateMessage("done");
        return null;
    }

}

Main.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main  extends Application {

    @Override
    public void start(Stage stage) {
        Group root = new Group();
        Scene scene = new Scene(root, 300, 150);
        stage.setScene(scene);
        stage.setTitle("Progress Controls");
        Button btn = new Button("call the thread");
        btn.setOnAction(new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent arg0) {
                threadDialog();
            }
        });
        VBox vb = new VBox();
        vb.getChildren().addAll(btn);
        scene.setRoot(vb);
        stage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
    private void threadDialog() {
        Stage stageDiag = new Stage();
        ParserTask pTask = new ParserTask();
        final Label loadingLabel = new Label("");
        loadingLabel.textProperty().bind(pTask.messageProperty());
        final ProgressBar pbar = new ProgressBar();
        pbar.setProgress(0);
        pbar.setPrefHeight(20);
        pbar.setPrefWidth(450);
        pbar.progressProperty().bind(pTask.progressProperty());
        GridPane grid = new GridPane();
        grid.setHgap(14.0);
        grid.add(loadingLabel, 0, 0);
        grid.add(pbar, 1, 1);
        Scene sceneDiag = new Scene(grid);
        stageDiag.setScene(sceneDiag);
        stageDiag.setTitle("Foo thread is loading");
        stageDiag.show();
        Thread parser = new Thread(pTask);
        parser.start();
        try {
            parser.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

如果,我评论/删除此代码:

If, I comment/ remove this code:

        try {
            parser.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

然后,我可以看到线程按预期加载,否则,我只能看到一个处于最终状态的空白屏幕(最后一条消息和完整的进度条)。

Then, I can see the thread loading as expected, otherwise, I can only see a blank screen that will be in the final state (the last message and the full progress bar).

    while(!loadingLabel.getText().contains("one")){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

甚至 while(解析器) .isAlive()); 没有成功。

我的问题是:我如何等待我的线程并保持用户界面工作?

My question is: How can I wait for my thread and keep the UI working?

推荐答案

你永远不应该阻止UI线程。

You should never block the UI thread.

背景的典型模式处理如下所示:

Typical pattern for background processing looks like follows:


  1. 更改UI以指示后台处理正在进行中(显示进度条,禁用按钮等)

  2. 启动后台线程

  3. 在后台线程中,处理完成后,更改UI并显示处理结果。应该使用 Platform.runLater() (以及从后台线程与UI交互的任何其他代码)

  1. Change UI to indicate that background processing is in progress (show progress bar, disable buttons, etc)
  2. Start a background thread
  3. In the background thread, after processing has finished, change the UI back and display processing results. Code that does it should be invoked using Platform.runLater() (as well as any other code that interacts with the UI from background threads)

简化示例:

btn.setOnAction(new EventHandler<ActionEvent>(){
    @Override
    public void handle(ActionEvent arg0) {
        // 1
        setBackgroundProcessing(true); 

        // 2
        new Thread() {
            public void run() {
                doProcessing();

                // 3
                Platform.runLater(new Runnable() {
                    public void run() {
                        displayResults();
                        setBackgroundProcessing(false);
                    }
                });
            }
        }.start();
    }
});

上面的代码不是很优雅,你可能想要使用线程池和/或 ListenableFuture s让它看起来更好。

The code above is not very elegant, you may want to use thread pools and/or ListenableFutures to make it look better.

这篇关于JavaFX多线程 - 加入线程不会更新UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆