【问题标题】:JavaFX Adding ThreadsJavaFX 添加线程
【发布时间】:2018-07-27 02:12:54
【问题描述】:

我使用 JavaFX 和 SceneBuilder 应用程序在 java 中编写了一个程序。我想为我的动作处理程序添加线程。此应用程序运行一个 python 脚本,该脚本发现文件并将其发送到 BACnet 网络上的适当设备。 python 脚本按预期工作,我的 java 应用程序按预期使用脚本。我的问题是更新 UI。该脚本返回的值显示了迄今为止的进度。当运行我的upgrade action handler 代码时,我想在执行executeCommand() 代码之前输出一条消息说“这应该需要 xx 分钟才能完成”,该代码也将输出写入 UI。然而,当upgrade action handler 退出时,所有更新都是同时写入的。

主要:

public class Main extends Application {

private Stage primaryStage;
private BorderPane rootLayout;

@Override
public void start(Stage primaryStage) {

    this.primaryStage = primaryStage;
    this.primaryStage.setTitle("NODE-Sensor Configurator");

    initRootLayout();

    showNodeConfigurator();

}

public void initRootLayout( ){
    try {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Main.class.getResource("view/RootLayout.fxml"));
        rootLayout = (BorderPane) loader.load();

        Scene scene = new Scene(rootLayout);
        primaryStage.setScene(scene);
        primaryStage.show();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void showNodeConfigurator(){
    try {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Main.class.getResource("view/NodeLayout.fxml"));
        AnchorPane nodeConfig;
        nodeConfig = (AnchorPane) loader.load();
        rootLayout.setCenter(nodeConfig);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public Stage getPrimaryStage(){
    return this.primaryStage;
}

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

我发送命令和写输出的代码:

@FXML
private Button upgrade;

upgrade.setOnAction((event) -> {

appendToOutputText("Reading in hex file");

python.executeCommand("readhexfile " + hexFile.getAbsolutePath());

appendToOutputText("Starting upgrade, this will take about 4 minutes to complete");
python.executeCommand("upgrade 158 158444");
)};

private void appendToOutputText(String message){
    outputTextArea.appendText(message + "\n");
}

我尝试将appendToOutputText 方法放在线程中,我尝试使用runLater JavaFX 代码,我什至尝试在操作处理程序中使用任务。我无法让这个输出正确地线程化。我没有找到使用场景构建器和 fxloader 的示例。

谁能阐明我如何将我的动作处理程序转变为线程任务,可以根据需要而不是在退出时更新 UI?

This Questions 看起来很有用。但是我不明白 FXLoader 将如何处理任务的概念。

【问题讨论】:

  • 我没有看到您的长时间运行的代码在 Thread 中的位置。
  • 为什么appendToOuptText 需要在Thread 中?从事情的角度来看,它没有。我猜你的Python 的东西需要在不同的Thread 上。
  • 你是对的,python脚本调用需要在另一个线程中。在我的脑海中,我虽然可以只线程化 'appendToOutputText' 方法并更新 UI

标签: java multithreading javafx


【解决方案1】:

鉴于您分享的信息有限,我认为您的代码应如下所示:

upgrade.setOnAction((event) -> {
    appendToOutputText("Reading in hex file");
    Task<Void> task1 = new Task<Void>() {
        @Override
        protected Void call() throws Exception {
            python.executeCommand("readhexfile " + hexFile.getAbsolutePath());
            return null;
        }
    };
    task1.setOnSucceeded((event) -> {
        appendToOutputText("Starting upgrade, this will take about 4 minutes to complete");
    });

    Task<Void> task2 = new Task<Void>() {
        @Override
        protected Void call() throws Exception {
            python.executeCommand("upgrade 158 158444");
            return null;
        }
    };
    task2.setOnSucceeded((event) -> {
        System.out.println("task2 done!");
    });


    ExecutorService es = Executors.newSingleThreadExecutor();
    es.submit(task1);
    es.submit(task2);
    es.shutdown();
)};

或者类似的东西:

upgrade.setOnAction((event) -> {
    appendToOutputText("Reading in hex file");
    Task<Void> task1 = new Task<Void>() {
        @Override
        protected Void call() throws Exception {
            python.executeCommand("readhexfile " + hexFile.getAbsolutePath());
            Platform.runLater(()->{appendToOutputText("Starting upgrade, this will take about 4 minutes to complete");});
            python.executeCommand("upgrade 158 158444");

            return null;
        }
    };
    task1.setOnSucceeded((event) -> {
        System.out.println("task1 done!");
    });

    ExecutorService es = Executors.newSingleThreadExecutor();
    es.submit(task1);
    es.shutdown();
)};

【讨论】:

    【解决方案2】:

    我认为您为 setOnAction() 传入的事件处理程序将在 JavaFx 应用程序线程中调用,因此您将能够操作 UI - 但对 executeCommand 的两个调用可能是阻塞调用。您需要创建两个后台线程:

    • 第一个后台线程通过 executeCommand() 启动外部命令,然后等待它完成。
    • 第二个后台线程启动并读取该外部命令产生的输出。第二个线程将进入一个循环,例如,每次它从外部命令读取新行时,第二个线程将调用 runLater() 向它传递一个代码块,该代码块将操纵 UI 以反映刚刚收到的数据.

    【讨论】:

    • 我完全理解,这完全有道理!你碰巧知道有什么很好的例子吗?这些线程是用 Thread 类创建的,它们是服务还是任务?
    • 我会制作 Runnables,然后将它们交给 ExecutorService - 这样您就可以在后台拥有一个线程池来处理您的所有后台工作......让它们成为任务将帮助您集成它们更好地融入 JavaFX UI - 除了(我设想它们的方式)这些将纯粹是背景,所以 Task 有点矫枉过正......
    • 只是一个快速的谷歌搜索把我带到stackoverflow.com/questions/29684597/… 我真的很感谢你的回答,因为它给了我很多研究!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-05
    • 2014-08-26
    • 1970-01-01
    • 2017-04-10
    • 1970-01-01
    相关资源
    最近更新 更多