Label update in loop

Asked

Viewed 460 times

0

How do I update a label in a loop in the tab FXMLDocumentController? The Abels only update after it completes the entire loop and then plays the last info 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) {

    }    

}

1 answer

0

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

To prevent the screen from locking, you need to create a separate thread to perform the desired operation. javafx provides two classes to work with threads: Task and Service. To read more about these two classes and about competition in javafx, see this link: https://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm

The method playBotao need to run in 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 is because the GUI is not thread-safe and so it does not allow another thread to change the screen components.

If you put the content of the method playBotao within a Task and have the code executed, an exception will be made to: 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 case the part that changes the value of the label, inside a Runnable and pass it to the method Platform.runLater(Runnable runnable). 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. Follow example of code:

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

Browser other questions tagged

You are not signed in. Login or sign up in order to post.