当前位置: 首页 > 知识库问答 >
问题:

更新 JavaFX 8 UI / Multithread

南宫凡
2023-03-14

几天来,我一直在尝试更新Javafx用户界面,同时自动发送2封或更多的电子邮件。UI应该用“连接”、“发送”和“已发送”来更新标签。我读过关于Runnables,Tasks,TimeLine的文章,但是我真的不知道我应该使用哪种方法,以及它是如何工作的。

在我阅读Platform.runLater()的任何地方,我都使用它,但是我的JavaFX Gui中的动画冻结了,只有当所有的电子邮件都已发送时,标签才会改变。

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

//编辑

谢谢你的帮助,布拉尼斯拉夫,但现在我得到了“不在外汇申请线程”-错误。下面的代码不是我的“扩展应用程序”类,请看一下。

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;
         }
     }
}

编辑2

现在程序正在一个接一个地发送电子邮件,但text属性无法正常工作。它没有刷新文本,它只清空标签。如果我删除取消绑定行(成功),它只在我运行发送任务时工作一次。之后,对于所有其他发送任务,它再次为空。

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(send test . message property());其中lblStatus1.textProperty()。unbind();?

共有1个答案

孟海
2023-03-14

您必须使用任务类。

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

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();

    }
}

事情很简单。你的耗时任务将冻结用户界面,直到它完成。通过使用< code>Task类,您的耗时任务在后台线程上运行,让JavaFX线程响应。有时,您可以从< code>call方法“发布”任务的结果。不要在后台线程上更新JavaFX UI(在< code>call方法中)。通过调用< code > platform . isfxaapplicationthread(),可以检查代码是否在< code > fxaapplicationthread 上运行。如果您的代码没有在那个线程上运行,不要从那里更新您的JavaFX UI!

 类似资料:
  • 我有一个问题与primeface数据表。我有一个数据与一些条目和一个列与一个按钮内。如果按钮被按下,一个弹出窗口打开与另一个数据表。第二个数据表中的条目取决于行中的按钮被按下。 Bean2 问题是弹出式数据表中没有列出任何条目,尽管在db查询之后的列表中有一些条目。 有没有办法修复这个bug?提前感谢! 更新1:

  • 我有一个表单,其中用户创建了一个编码问题。在表单中,可以通过输入和输出文本框添加示例测试用例。用户可以单击按钮添加新的测试用例。现在我有一个state对象,它保存所有表单数据formObj,其中有一个示例_test_cases字段,我想保存一个对象数组,比如:[{input:,output::}]。 我遇到的问题是更新此阵列。我需要能够在每次添加测试用例时将一个新对象连接到它。然后在文本框更改时更

  • Flarum 正处于测试阶段,有关如何更新的说明将在每次 版本发布公告中公示。

  • 如果你想和社区以及开发版的 Requests 保持最新的联系, 这有几种方式: GitHub 最好的方式是追踪 Requests 开发版本的 GitHub 库. Twitter 我经常推送关于 Requests 的新功能和新版本. 关注 @kennethreitz 即可获得更新。 Release History dev Improvements Bugfixes 2.18.1 (2017-06-1

  • 和模型新增一样,更新操作同样也会经过修改器、自动完成以及模型事件等处理,并不等同于数据库的数据更新,而且更新方法和新增方法使用的是同一个方法,通常系统会自动判断需要新增还是更新数据。 查找并更新 在取出数据后,更改字段内容后使用save方法更新数据。这种方式是最佳的更新方式。 $user = User::get(1); $user->name = 'thinkphp'; $user->em

  • Yearning采用自动表结构同步 无需手动更新表结构。只需停止原服务并替换安装包后重新启动即可 在一些特殊的升级情况中(破坏性变更)需要手动进行数据同步操作.如在版本更新公告中并无提示破坏性升级则无视以下命令! ./Yearning migrate

  • 我正在制作一个由任务管理器组成的应用程序。 在此任务管理器中,收件箱列表中有3个列表(收件箱、今天和星期),其中仅显示不带类别的任务,而在其他两个列表中,分别显示今天和本周的带类别或不带类别的任务。 我希望能够更改三个列表中一个任务的类别。因此,如果我更改收件箱任务的类别(不应该有类别),整个表都应该更新,任务应该从列表中删除。 我调试了程序,任务被正确地从列表中删除,但只有类别的单元格被更新,而

  • 问题内容: 我正在通过ng-repeat循环渲染数据。而且我希望它在更新数组时进行更新。从我阅读的内容来看,这应该会自动发生,但是这是行不通的。那我在做什么错? 的HTML: 控制器(此功能通过ng-click在按钮上触发): Console.log显示该数组已正确更新,但是我视图中的表未更改。我不知道我在做什么错。 问题答案: 那是因为您在method中更改了数组引用。 为了避免这种情况,我们使