更新JavaFX 8 UI /多线程 [英] Update JavaFX 8 UI / Multithread

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

问题描述

好几天我现在正在尝试更新Javafx用户界面,同时自动发送2个或更多电子邮件。 UI应该使用连接,发送和已发送更新标签。我读过关于Runnables,Tasks,TimeLine但我真的不明白我应该使用哪种方法以及它是如何工作的。

for days now i am trying to update a Javafx userinterface while sending 2 or more E-Mails automatically. The UI should update a Label with "connecting", "sending" and "sent". I've read about Runnables, Tasks, TimeLine but i dont really understand which method i should use and how it works.

无论我在哪里阅读有关Platform.runLater()的内容,我都使用了它,但是当我发送了所有电子邮件时,我的JavaFX Gui中的动画会冻结而Label只会更改。

Everywhere i read about Platform.runLater(), I used it but the animation in my JavaFX Gui freezes and the Label only changes, when all E-Mails have been sent.

我会很快用我的代码更新这篇文章,但有人可以告诉我应该使用哪种线程以及如何轻松更新ui?

I will update this post with my code soon, but can someone already tell me what kind of Thread i should use and how the ui can be updated easily?

//编辑

感谢你的帮助,Branislav但现在我得到了Not on FX application thread - 错误。下面的代码不是我的扩展应用程序类,请看一下。

thanks for your help, Branislav but now im getting the "Not on FX application thread"-Error. The following code is not my "extends Application"-class, please take a look.

public class ControllerOCM implements Initializable{



    @FXML
    private ComboBox<String> comboEmpf;

    @FXML
    private Label lblStatus;

    @FXML
    private Label lblStatus1;


    @Override
    public void initialize(URL location, ResourceBundle resources) {
        hint.setText("some hint");
    }

    public void sende(ActionEvent event) throws Exception {

        switch (comboEmpf.getValue()) {
        case "A": System.out.println("A");break;
        case "B":
        File fTEST = new File("C:\\B\\");
        File[] fpathTEST = fTEST.listFiles();
        String[] fnameTEST = fTEST.list();

    for (int i=0; i<fpathTEST.length; i++) {
        SendenTask sendTEST = new SendenTask(mail@address.com,
                "bodycontent",
                "subject", 
                fpathTEST[i].toString(),    
                fnameTEST[i],               
                i,                      //count
                fpathTEST.length);      //max

        new Thread(sendTEST).start();
    }
            break;
        }
    }

     public class SendenTask extends Task<Void> {
            private String adr;
            private String body;
            private String subj;
            private String fp;
            private String fn;
            private int count;
            private int max;

         public SendenTask(String adr, String body, String subj, String fp, String fn, int count, int max) {
            this.adr = adr;
            this.body = body;
            this.subj = subj;
            this.fp = fp;
            this.fn = fn;
            this.count = count;
            this.max = max;

         }

         @Override 
         protected Void call() throws Exception {

         lblStatus1.setText("connecting");
         //doing connectionAction

         lblStatus1.setText("sending");
         updateMessage("sending");
         //doing sendingthingys


         //sending complete
         lblStatus1.setText("sent");
         System.out.println("done");
         updateMessage("done");

             return null;
         }
     }
}

// edit2

现在程序正在逐个发送电子邮件,但textproperty无法正常工作。它没有刷新文本,它只是清空标签。如果我删除unbind-line(成功)它只运行一次我发送任务。之后,对于所有其他发送任务,它再次为空。

Now the programm is sending Emails one after another but the textproperty is not working correctly. It is not refreshing the text, it only emptys the label. If i remove the unbind-line (in succeed) it only works one time i run the send task. After that it is empty again for all other send tasks.

public class ControllerOCM implements Initializable{



        @FXML
        private ComboBox<String> comboEmpf;

        @FXML
        private Label lblStatus;

        @FXML
        private Label lblStatus1;


        @Override
        public void initialize(URL location, ResourceBundle resources) {
            hint.setText("some hint");
        }

        public void sende(ActionEvent event) throws Exception {

            switch (comboEmpf.getValue()) {
            case "A": System.out.println("A");break;
            case "B":
            File fTEST = new File("C:\\B\\");
            File[] fpathTEST = fTEST.listFiles();
            String[] fnameTEST = fTEST.list();

        for (int i=0; i<fpathTEST.length; i++) {
            SendenTask sendTEST = new SendenTask(mail@address.com,
                    "bodycontent",
                    "subject", 
                    fpathTEST[i].toString(),    
                    fnameTEST[i],               
                    i,                      //count
                    fpathTEST.length);      //max

              lblStatus1.textProperty().bind(sendTEST.messageProperty());
              thread = new Thread(sendTEST);
              thread.start();   
              }
              break;
            }
        }

         public class SendenTask extends Task<Void> {
                private String adr;
                private String body;
                private String subj;
                private String fp;
                private String fn;
                private int count;
                private int max;

             public SendenTask(String adr, String body, String subj, String fp, String fn, int count, int max) {
                this.adr = adr;
                this.body = body;
                this.subj = subj;
                this.fp = fp;
                this.fn = fn;
                this.count = count;
                this.max = max;

             }

             @Override 
             protected Void call() throws Exception {

             while(!sending) {
             sending = true

             updateMessage("connecting");
             //doing connectionAction


             updateMessage("sending");
             //doing sendingthingys


             //sending complete
             updateMessage("done");
                 }
                 return null;
             }
     @Override
     protected void succeeded() {
         super.succeeded();
         lblStatus1.textProperty().unbind();
         sending = false;
         }
       }

    }

// edit3
最大的问题是,我在哪里放置
lblStatus1.textProperty()。bind(sendTEST.messageProperty());

lblStatus1.textProperty()。unbind();

推荐答案

你必须使用 任务 class。

You have to use Task class.

这是一个小型演示。让我们通过循环来模拟耗时的任务循环:

Here is a small demo. Let's simulate time consuming task via for loop:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;


public class TaskDemo extends Application {


    @Override
    public void start(Stage stage) throws Exception {
        final Label label = new Label();

        Task<Void> task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                boolean fxApplicationThread = Platform.isFxApplicationThread();
                System.out.println("Is call on FXApplicationThread: " + fxApplicationThread);
                // Run your time consuming task here!
                for (int i = 0; i < 10; i++) {
                    Thread.sleep(1000);
                    updateMessage("Time elapsed: " + i);
                }
                return null;
            }

            @Override
            protected void succeeded() {
                boolean fxApplicationThread = Platform.isFxApplicationThread();
                System.out.println("Is call on FXApplicationThread: " + fxApplicationThread);
                super.succeeded();
                label.textProperty().unbind();
                label.setText("Task done");
            }
        };
        // Bind messageProperty of task for textProperty of Label
        label.textProperty().bind(task.messageProperty());
        stage.setScene(new Scene(label, 300, 200));
        stage.show();
        new Thread(task).start();

    }
}

事情很简单。您的耗时任务将冻结UI直到完成。通过使用 Task 类,您的耗时任务在后台线程上运行,从而使JavaFX线程响应。有时,您可以从调用方法发布任务结果。 不要在后台线程上更新您的JavaFX UI(在 call 方法中)。通过调用 Platform.isFxApplicationThread(),您可以检查您的代码是否在 FXApplicationThread 上运行。如果您的代码没有在该线程上运行,请不要从那里更新JavaFX UI!

Things are simple. Your time consuming task will freeze UI until it finishes. By using Task class, your time consuming task runs on background thread leaving JavaFX thread responsive. Occasionally, you can "publish" results of your task from call method. DO NOT update your JavaFX UI on background thread (in call method). By calling Platform.isFxApplicationThread() you can check whether your code runs on FXApplicationThread. If your code is not running on that thread, do not update your JavaFX UI from there!

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

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