JAVAFX如何更新GUI元素(节点)

时间:2016-05-02 21:42:29

标签: java multithreading user-interface javafx

这个问题已经被问到了,但是我已经提出了这个问题。设想。我有一个有2个场景的程序。首先打开scene1,这是连接数据库的场景。有一个名为Status的标签,当建立连接时(通过单击COnnect按钮),该标签应从“Disconnected”变为“Connected”。所以我做了一个函数来接受onClick事件的“连接”按钮。此函数在控制器类中声明和定义(我使用场景构建器进行fmxl设计)。所以基本上我想从控制器类内部的连接函数(方法)将状态更改为“COnnected”(status.setText(“Connected”))。但是,当我这样做时,文本在建立连接后不会立即更改,但是当场景即将关闭时它会改变,我即将把场景更改为新场景...我在互联网上阅读我看到我应该使用Platform.runLater和线程,所以我尝试了:

private void changeSC() throws IOException, InterruptedException, SQLException
{

    dbConnect();

    Thread thrd = new Thread() {

        public void run() {

                 Platform.runLater(new Runnable() {
                     @Override public void run() {
                     status.setText("Connected");
                        status.setTextFill(Color.GREEN);
                     }});
        }
    };
    thrd.start();

    //pb.setProgress(1.0);
    Parent root = FXMLLoader.load(getClass().getResource("Design.fxml"));
    Scene primary = new Scene(root,1024,768);
    primary.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
    System.out.println("Text changing to COnnected");
    status.setTextFill(Color.GREEN);
    Thread.sleep(2000);
    Main.window.setScene(primary);

}

changeSC是单击“连接”按钮时执行的功能。这是我的旧版本,也不起作用:

private void changeSC() throws IOException, InterruptedException, SQLException
{

    dbConnect();

      status.setText("Connected");
      status.setTextFill(Color.GREEN);


    //pb.setProgress(1.0);
    Parent root = FXMLLoader.load(getClass().getResource("Design.fxml"));
    Scene primary = new Scene(root,1024,768);
    primary.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
    System.out.println("Text changing to COnnected");
    status.setTextFill(Color.GREEN);
    Thread.sleep(2000);
    Main.window.setScene(primary);

}

问题在于文本应该更改为“已连接”。当我的场景即将被切换时它会改变....

3 个答案:

答案 0 :(得分:3)

如果您有一些长时间运行的操作,则需要使用Task。否则,当从JavaFX应用程序线程调用该操作时,它将阻止GUI。

如果要从Task更新GUI,则必须使用Platform.runlater,这将运行JavaFX应用程序线程上的代码: Platform.runlater

总是要在JavaFx线程上执行GUI Nodes的更新。

当您在status的{​​{1}}内更新Listener时,它应该有效。

button

如果 button.setOnAction(evt -> { dbConnect(); status.setText("Connected"); // ... }); 需要一些时间,您可以使用dbConnect()

Task

答案 1 :(得分:0)

由于您要连接到数据库,因此应该使用TaskService将此代码放在后台运行,以使GUI线程响应用户输入。请记住,只有在GUI线程中,您才能更新视图状态(更改案例中文本的值)。您可以使用java Thread并使用Platform.runLater,这意味着内部代码计划由GUI Thread进行,但在您的情况下,您使用的方式是错误的。首先,连接数据库的逻辑应该在线程的方法run内,一旦方法完成,设置文本的值并做任何你想要的事情。此外,您还需要在完成所有过程后显示新的Scene,以便让用户有机会查看文本中的更改。您可以通过以下方式更改代码:

private void changeSC() throws IOException, InterruptedException, SQLException
{
  Thread thrd = new Thread() {

    public void run() {
        dbConnect();
        Platform.runLater(new Runnable() {
             @Override public void run() {
                 status.setText("Connected");
                 status.setTextFill(Color.GREEN);
                 //pb.setProgress(1.0);
                 Parent root = FXMLLoader.load(getClass().getResource("Design.fxml"));
                 Scene primary = new Scene(root,1024,768);
                 primary.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
                 System.out.println("Text changing to COnnected");
                 status.setTextFill(Color.GREEN);
                 Main.window.setScene(primary);
              }
        });
     }
  };
  thrd.start();
}

如果您选择使用Task,则无需明确处理Platform.runLater。您只需要创建一个任务(类Task的实现),将其包装在java Thread中,启动它并为不同的事件设置处理程序(例如:setOnSucceeded )。这是使用Task的代码:

private void changeSC() throws IOException, InterruptedException, SQLException
{  
    Task<Void> task = new Task<Void>(){
        @Overrdie
        protected Void call()  {
            dbConnect();   
            return null;
        }
    };
    //start Task
    Thread t = new Thread(task);
    t.setDaemon(true); // thread will not prevent application shutdown
    t.start();

    task.setOnSucceeded(event -> {
        Parent root = FXMLLoader.load(getClass().getResource("Design.fxml"));
        Scene primary = new Scene(root,1024,768);
        primary.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        System.out.println("Text changing to COnnected");
        status.setTextFill(Color.GREEN);
        Main.window.setScene(primary);
    });


}

答案 2 :(得分:-2)

好吧我通过设置task.SetonFailed()来修复它:)