JavaFX:在单独的非控制器类中更新UI [英] JavaFX: update UI in separate, non-controller class

查看:200
本文介绍了JavaFX:在单独的非控制器类中更新UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个JavaFX程序,它启动由单独的类执行的任务。我想将该任务的进度状态输出到UI中的 Label 元素。我不能让这个工作。这是我的代码:

I have a JavaFX program that launches a task performed by a separate class. I would like to output the status of that task's progress to a Label element in the UI. I cannot get this to work. Here is my code:

Main.java:

public class Main extends Application {
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("ui.fxml"));
        primaryStage.setTitle("Data collector");
        primaryStage.setScene(new Scene(root, 400, 400));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Controller.java:

我要更新的标签是通过全局去除来创建的 @FXML public Label label = new Label(); 。通过 new Thread创建一个新线程(new Task< Void>(){...})。start(); 运行 collect_data 来自 TaskRun 的方法。 TaskRun 类如下所示:

The label I want to update is created by delcaring globally @FXML public Label label = new Label();. Creates a new thread via new Thread(new Task<Void>() { ... }).start(); to run the collect_data method from TaskRun. The TaskRun class is stated below:

TaskRun.java:

class TaskRun {
    private Controller ui;

    TaskRun() {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("ui.fxml"));
        ui = loader.getController();
    }

    void collect_data() {
        for (int i = 0; i < 100; i++) {
            // do stuff...
            send_progress_to_ui(((float) i / (float)) * 100);
        }
    }

    void send_progress_to_ui(float percent) {
        new Thread(new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                Platform.runLater(() -> ui.label.setText(Float.toString(percent_complete) + "%"));

                return null;
            }
        }).start();
    }

}

我得到 NullPointerException Platform.runLater(...)的行上。

很明显,这种方法不起作用。如何通过此非控制器类更新UI TaskRun

So obviously, this method is not going to work. How do I update the UI through this non-controller class TaskRun?

推荐答案

你的设计对你在这里尝试做的事情并没有多大帮助。而不是一个完全隐藏任务并创建一个线程来运行它的类(这是非常不灵活的:如果你想将任务提交给现有的 Executor ?),你的班级应该执行任务。然后你可以只更新任务的进度,这是一个可观察的属性:

Your design is not really very helpful for what you are trying to do here. Instead of a class that hides the task entirely and creates a thread to run it (which is really inflexible: what if you want to submit the task to an existing Executor?), your class should implement the task. Then you can just update the task's progress, which is an observable property:

class TaskRun extends Task<Void> {

    @Override
    protected Void call() {
        for (int i = 0; i < 100; i++) {
            // do stuff...
            updateProgress(i, 100);
        }
        return null ;
    }

}

现在在控制器中你可以执行:

Now in your controller you can just do:

TaskRun task = new TaskRun();
task.progressProperty().addListener((obs, oldProgress, newProgress) -> 
    label.setText(String.format("%.2f percent complete", newProgress.doubleValue()*100)));
new Thread(task).start();

或者,使用绑定而不是监听器:

Alternatively, use a binding instead of the listener:

label.textProperty().bind(task.progressProperty().asString("%.2f percent complete"));

这消除了你所有可怕的耦合,因为现在 TaskRun 不需要知道控制器类的任何信息。

This gets rid of all the horrendous coupling you have, because now TaskRun doesn't need to know anything about the controller class.

这篇关于JavaFX:在单独的非控制器类中更新UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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