Update label in loop

1

How do I update a label in a loop on the FXMLDocumentController ? The labels only update after the entire loop is finished and then plays the last information on the screen;

package musicaisfx;

import java.awt.Font;
import java.awt.event.PaintEvent;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javax.swing.text.BadLocationException;

public class FXMLDocumentController implements Initializable {

    @FXML
    private Label label;
    String frase = "bbb " ;
    @FXML
   private void playBotao(ActionEvent event) throws Exception {


       char letras[] = frase.toCharArray();
       for (int i = 0 ;i < letras.length; i++) {
           label.setText("b");
              frase=frase+frase;     
           Font name=Font.getFont("LASSUS");
           label.setStyle("-fx-font-family:Arial");
           label.setText(frase);
            Thread.sleep(500);




           System.out.println(frase);

       }

    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {

    }    

}
    
asked by anonymous 30.05.2017 / 07:53

1 answer

0

The problem is that the code has only one thread. When the playBotao method is called, the screen is locked because the method is running in the same thread as the screen. Therefore, it is only after the method finishes executing that the screen will be able to update its components.

To prevent the screen from being blocked, you must create a separate thread to perform the desired operation. Javafx provides two classes for working with threads: Task and Service . To read more about these two classes and about competition in javafx, see this link: link

The playBotao method needs to run on a separate thread, so while the method is changing the label value, the GUI thread will update the label. An important detail is that only the GUI thread (commonly called the javafx thread) can change the screen components. This happens because the GUI is not thread safe and therefore it does not allow another thread to change the components of the screen.

If you put the contents of the playBotao method inside a Task and have the code executed, an exception is thrown: java.lang.IllegalStateException: Not on FX application thread . To avoid this error, you need to put the part of the code that changes components of the screen, in this case the part that changes the value of the label, inside a Runnable and pass it to the Platform.runLater(Runnable runnable) method. This method will execute the desired code in the javafx thread at some point in the future. In this case, you will see that the solution will work well. Here is a code example:

private String frase = "bbb ";

    @Override
    public void start(Stage primaryStage) {
        try {
            GridPane gridPane = new GridPane();
            Label label = new Label("João");
            Button button = new Button("Alterar Label");
            button.setOnMouseClicked(event -> {
                Task<Void> task = new Task<Void>(){
                    @Override
                    protected Void call()  {

                        char letras[] = frase.toCharArray();
                        for (int i = 0 ;i < letras.length; i++) {
                            // Necessário para que não ocorra:
                            //java.lang.IllegalStateException: Not on FX application thread
                            //O trecho será executado na thread do javafx
                            Platform.runLater(() -> {
                                label.setText("b");
                                frase=frase+frase;     
                                label.setStyle("-fx-font-family:Arial");
                                label.setText(frase);

                            });
                            try {
                                Thread.sleep(500);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println(frase);
                        }
                        return null;
                    }
                };
                Thread thread = new Thread(task);
                thread.setName("task-change-label");
                thread.setDaemon(true);
                thread.start();
            });

            gridPane.add(button, 0, 0);
            gridPane.add(label, 1, 0);

            Scene scene = new Scene(gridPane,400,400);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
03.12.2017 / 03:46