0

I have an issue when trying to modify a JavaFx label, created using SceneBuilder, in an asynchronous manner using runLater().

I can modify it from a callback triggered from a button, but when I try to access to the same element from the runLater method I get an error statting that this element is null.

The error code:

    jun 30, 2021 3:42:25 P. M. javafx.fxml.FXMLLoader$ValueElement processValue
WARNING: Loading FXML document with JavaFX API of version 16 by JavaFX runtime of version 11.0.2
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException: Cannot invoke "javafx.scene.control.Label.setText(String)" because "this.texto" is null
    at test.view.GuiApp.lambda$0(GuiApp.java:58)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:831)

My code:

public class GuiApp extends Application{
    private Region rootLayout;  
    private Stage stage;
    
    @FXML private Pane tankPane;
    
    @FXML public Label texto ;  
    public static GuiApp main;      
    
    @Override
    public void start(Stage primaryStage) throws IOException {      
        main = this;
                
        stage = primaryStage;
        stage.setTitle("mainStage");
        stage.setResizable(false);  
        
        // Load root layout from fxml file.
        FXMLLoader loader = new FXMLLoader();         
        loader.setLocation(GuiApp.class.getResource("main.fxml"));      
        rootLayout = (Region) loader.load();  
        
        // Show the scene containing the root layout.               
        Scene scene = new Scene(rootLayout);         
        stage.setScene(scene);      
        stage.show();
        
        Platform.runLater(() -> texto.setText("klfdsfklañsd"));
    }
    
    public static void main(String[] args) {        
        launch(args);
    }   
    
    @FXML
    public void updateRandom()
    {
     Random r = new Random();
     texto.setText(Float.toString(r.nextFloat()));
    }          
     @FXML
     private void onReload() {       
         updateRandom();
     }
}

I have tried to reduce it to the simplest, and sorry for my english by the way.

James_D
  • 201,275
  • 16
  • 291
  • 322
ejht
  • 1
  • 3
    1. Don't use the `Application` class as the controller class. 2. There is no point in `Platform.runLater(...)` here; you are already on the FX Application Thread. 3. The problem is nothing to do with `Platform.runLater(...)`: `texto` is null. It is only initialized in the `GuiApp` instance that is created as the controller (when you load the FXML), it is not initialized in the `GuiApp` instance that is created when the application starts up (and on which `start()` is invoked). – James_D Jun 30 '21 at 14:01
  • Thank you so much, it was exactly that, I am new in JavaFx and I was a little confused, I have created a controller class and use the runLater in this class and this is working fine. – ejht Jun 30 '21 at 16:05
  • But why are you using `Platform.runLater()` at all here? That doesn't make sense. – James_D Jun 30 '21 at 16:05
  • I was just getting familiar with it, the complete point is to update with data incoming from serial commuication with a sensor. – ejht Jun 30 '21 at 16:07
  • But then you need that to run on a background thread. The last thing you want is to do that on the FX Application thread. – James_D Jun 30 '21 at 16:08
  • So whick would be the best approach? Maybe using Task? I have read in blogs that runlater could fit for my application but maybe I am wrong. – ejht Jun 30 '21 at 16:16
  • A `Task` is probably the correct approach. See https://stackoverflow.com/questions/30249493/using-threads-to-make-database-requests – James_D Jun 30 '21 at 16:23

0 Answers0