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