JavaFx - 更新图形用户界面

11
我想要的是在程序运行时更新标签。我正在读取一些文件,希望能显示正在读取的文件名。
然而,使用以下代码只会显示最后一个文件(基本上GUI在整个过程完成之前都不会响应):
static Text m_status_update = new Text(); //I declared this outside the function so dont worry
m_status_update.setText("Currently reading " + file.getName());

我有大约4-5个文件,我只想显示它们的名字。

我看到了一个类似的问题在JavaFx Label中显示变化的值,最佳答案建议使用以下方法:

Label myLabel = new Label("Start"); //I declared this outside the function so dont worry
myLabel.textProperty().bind(valueProperty);

然而valueProperty是一个StringProperty,我现在卡在将字符串转换为字符串属性的步骤中。

另外,我看到了这个在JAVAFX中刷新标签,但原帖的提问者能够基于动作更新标签。而我没有任何动作可以执行?


这听起来可能是一个线程问题,但仅凭几个代码片段无法确定。您能否从头开始创建一个MCVE,以演示问题? - James_D
但是我只有一个线程。好的,我会添加更多细节。 - Indigo
如果您正在FX应用程序线程上运行整个过程,那么这就是问题所在。 - James_D
如果我在一个线程上运行所有东西会有什么问题吗?我的意思是,我点击单选按钮。点击提交。获取目录中的文件。迭代它们并显示我正在迭代的文件。 - Indigo
1个回答

18

如果您在FX应用程序线程上运行整个过程,那么实际上就是使用于显示UI的同一线程。如果UI的显示和文件迭代进程都在同一线程中运行,那么只能同时进行一个操作。所以您需要等待该进程完成,才可以更新UI。

这里有一个简单的例子,我只是在每次迭代之间暂停250毫秒(模拟读取一个相当大的文件)。一个按钮可以在FX应用程序线程中启动它(请注意,在此运行时UI无响应-您无法在文本字段中输入文字)。另一个按钮使用Task在后台运行它,并正确地在FX应用程序线程上安排更新UI。

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;


public class UpdateTaskDemo extends Application {

    @Override
    public void start(Stage primaryStage) {
        Label label = new Label();
        Button runOnFXThreadButton = new Button("Update on FX Thread");
        Button runInTaskButton = new Button("Update in background Task");
        HBox buttons = new HBox(10, runOnFXThreadButton, runInTaskButton);
        buttons.setPadding(new Insets(10));
        VBox root = new VBox(10, label, buttons, new TextField());
        root.setPadding(new Insets(10));

        runOnFXThreadButton.setOnAction(event -> {
            for (int i=1; i<=10; i++) {
                label.setText("Count: "+i);
                try {
                    Thread.sleep(250);
                } catch (InterruptedException exc) {
                    throw new Error("Unexpected interruption");
                }
            }

        });

        runInTaskButton.setOnAction(event -> {
            Task<Void> task = new Task<Void>() {
                @Override 
                public Void call() throws Exception {
                    for (int i=1; i<=10; i++) {
                        updateMessage("Count: "+i);
                        Thread.sleep(250);
                    }
                    return null ;
                }
            };
            task.messageProperty().addListener((obs, oldMessage, newMessage) -> label.setText(newMessage));
            new Thread(task).start();
        });

        primaryStage.setScene(new Scene(root, 400, 225));
        primaryStage.show();
    }

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接