Multithreading 如何在JavaFX中从单独的线程更新状态和进度

Multithreading 如何在JavaFX中从单独的线程更新状态和进度,multithreading,textarea,javafx-2,output,Multithreading,Textarea,Javafx 2,Output,我需要能够调用一个单独的线程。线程分析一个文件并从中提取统计信息 分析文件可能需要2分钟,分析期间,数据会打印到日志中 我想在前端有一个文本区,需要打印出分析(因为它是分析),我还想有一个进度条来指示进度。所有这些都是在单独的线程内确定的 我所做的是在UI类中创建一个方法,向文本区域添加一个字符串,并将该类的引用传递给启动的线程 我的主课 package trymutilthread; import javafx.application.Application; import javafx.a

我需要能够调用一个单独的线程。线程分析一个文件并从中提取统计信息

分析文件可能需要2分钟,分析期间,数据会打印到日志中

我想在前端有一个文本区,需要打印出分析(因为它是分析),我还想有一个进度条来指示进度。所有这些都是在单独的线程内确定的

我所做的是在UI类中创建一个方法,向文本区域添加一个字符串,并将该类的引用传递给启动的线程

我的主课

package trymutilthread;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TryMutilThread extends Application {

    TextArea ta;

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

    @Override
    public void start(Stage primaryStage) {
        Button btn = new Button();
        btn.setText("Start");
        btn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                startScheduledExecutorService();
            }
        });

        ta = new TextArea();        

        VBox vBox = new VBox();
        vBox.getChildren().addAll(btn, ta);

        StackPane root = new StackPane();
        root.getChildren().add(vBox);

        Scene scene = new Scene(root, 300, 750);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void startScheduledExecutorService() {
        final TryMutilThread classI = this;

        Task<Void> task = new Task<Void>() {
            @Override protected Void call() throws Exception {
                try {
                    ta.appendText("Starting Thread\n");
                    new SomeProcess(classI).doTheLogic();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
        };

        Thread th = new Thread(task);
        th.setDaemon(true);
        th.start();      
    }

    public void appendText(String string) {        
        ta.appendText(string);
    }
}   
然后我用谷歌搜索错误,似乎我需要将交互代码放在一个平台上。runlater()

我更改了类以执行要执行的线程

package trymutilthread;

import javafx.application.Platform;

public class SomeProcess {

    TryMutilThread taClass = null;

    public SomeProcess(TryMutilThread taClass) {
        this.taClass = taClass;
    }

    public void doTheLogic() throws Exception {
        taClass.appendText("Staring Thread");

        for (int i = 0; i < 5000; i++) {
            //remove this append line
            //taClass.appendText(i + "\n");                
            //And replaced it with platform.runlater
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    taClass.appendText("AGREED" + "\n");
                }
            });
        }

        taClass.appendText("Ending Thread");
    }
}
包trymutilthread;
导入javafx.application.Platform;
公共类进程{
TryMutilThread taClass=null;
公共进程(TryMutilThread taClass){
this.taClass=taClass;
}
public void doTheLogic()引发异常{
taClass.appendText(“起始线程”);
对于(int i=0;i<5000;i++){
//删除此附加行
//taClass.appendText(i+“\n”);
//并将其替换为platform.runlater
Platform.runLater(新的Runnable(){
@凌驾
公开募捐{
taClass.appendText(“同意”+“\n”);
}
});
}
taClass.appendText(“结束线程”);
}
}

它执行时没有任何错误,但现在似乎又回到了起点。。。UI被冻结,直到所有内容都添加到TextArea

问题在于,FX应用程序线程中的请求太多;在Platform.runLater(…)调用之间没有实际的工作发生。这个问题可能会随着实际应用程序而不是本测试而消失,但是为了模拟实际的长时间运行工作,您可以在其中放置一个线程。sleep(…):

import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class TextAreaBackgroundUpdateExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        final BorderPane root = new BorderPane();
        final TextArea textArea = new TextArea();
        final ProgressBar progress = new ProgressBar();
        final Button startButton = new Button("Start");

        final int maxCount = 5000 ;

        startButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Task<Void> task = new Task<Void>() {
                    @Override
                    protected Void call() throws Exception {
                        for (int i = 1; i <= maxCount; i++) {
                            Thread.sleep(10);
                            final int count = i ;
                            Platform.runLater(new Runnable() {
                                @Override
                                public void run() {
                                    textArea.appendText("Processed part " + count + " (of "+maxCount+")\n");                                    
                                }
                            });
                            updateProgress(i, maxCount);
                        }
                        return null;
                    }
                };
                progress.progressProperty().bind(task.progressProperty());
                Thread t = new Thread(task);
                t.setDaemon(true);
                t.start();
            }
        });

        root.setCenter(textArea);
        root.setTop(progress);
        root.setBottom(startButton);

        final Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}
导入javafx.application.application;
导入javafx.application.Platform;
导入javafx.concurrent.Task;
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.control.ProgressBar;
导入javafx.scene.control.TextArea;
导入javafx.scene.layout.BorderPane;
导入javafx.stage.stage;
公共类TextAreaBackgroundUpdateExample扩展应用程序{
@凌驾
公共无效开始(阶段primaryStage){
最终边界窗格根=新边界窗格();
最终TextArea TextArea=新TextArea();
最终进度条进度=新进度条();
最终按钮开始按钮=新按钮(“开始”);
最终整数最大计数=5000;
setOnAction(新的EventHandler(){
@凌驾
公共无效句柄(ActionEvent事件){
任务=新任务(){
@凌驾
受保护的Void调用()引发异常{

对于(int i=1;i您的示例代码中没有后台线程;所有内容都在FX应用程序线程上运行。最好的方法是使用javafx.concurrent.Task。请参阅有很多示例的。James i更新了代码以使用任务。这似乎可行,但只要我有足够的代码添加,它似乎就实现了ning设置为fast,我得到了一个空指针。我搜索了错误,似乎应该在平台中添加代码。runLater(),但这再次冻结了UI。我用详细的注释修改了我的问题。
package trymutilthread;

import javafx.application.Platform;

public class SomeProcess {

    TryMutilThread taClass = null;

    public SomeProcess(TryMutilThread taClass) {
        this.taClass = taClass;
    }

    public void doTheLogic() throws Exception {
        taClass.appendText("Staring Thread");

        for (int i = 0; i < 5000; i++) {
            //remove this append line
            //taClass.appendText(i + "\n");                
            //And replaced it with platform.runlater
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    taClass.appendText("AGREED" + "\n");
                }
            });
        }

        taClass.appendText("Ending Thread");
    }
}
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class TextAreaBackgroundUpdateExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        final BorderPane root = new BorderPane();
        final TextArea textArea = new TextArea();
        final ProgressBar progress = new ProgressBar();
        final Button startButton = new Button("Start");

        final int maxCount = 5000 ;

        startButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Task<Void> task = new Task<Void>() {
                    @Override
                    protected Void call() throws Exception {
                        for (int i = 1; i <= maxCount; i++) {
                            Thread.sleep(10);
                            final int count = i ;
                            Platform.runLater(new Runnable() {
                                @Override
                                public void run() {
                                    textArea.appendText("Processed part " + count + " (of "+maxCount+")\n");                                    
                                }
                            });
                            updateProgress(i, maxCount);
                        }
                        return null;
                    }
                };
                progress.progressProperty().bind(task.progressProperty());
                Thread t = new Thread(task);
                t.setDaemon(true);
                t.start();
            }
        });

        root.setCenter(textArea);
        root.setTop(progress);
        root.setBottom(startButton);

        final Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }


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