javanullpointerexceptionjavafxfxmlsettext

label.setText NullPointerException


Hi first time here but here goes:

I have a JavaFX application that changes the FXML UI labels dynamically and the data is pulled from a Player class.

The two classes in question are Player.java and InterfaceHandler.java.

The player class stores player details and I want to pass the details to the Interface class which sets the text on the labels.

As a test my FXML UI just has a button and two labels.

If it click the button it calls the handleButton method it sets locationLabel to "Town" fine.

However if I call the locationLabel() method in my Player class I get a NullPointerException when nameLabel.setText(name) is called. Through debugging I find that the name string in the Interface class is what it should be "Dan".

Can anyone help?

Main class:

public class Main extends Application {

    public void start(final Stage mainStage) throws Exception {

        Parent root = FXMLLoader.load(getClass().getResource("MainScreen.fxml"));
        Scene scene = new Scene(root);
        mainStage.setTitle("Main Screen");
        mainStage.setScene(scene);
        mainStage.show();    
    }

public static void main(String[] args) {
        launch(args);
    }
}

Player class:

public class Player{

InterfaceHandler ui = new InterfaceHandler();   

 public void setNameLabel() {

    String name = "Dan";
    ui.setName(name);
}

InterfaceHandler class:

    public class InterfaceHandler implements Initializable {

       public Label nameLabel;
       public Label locationLabel;    

public void handleButton(ActionEvent event) throws IOException {        

        locationLabel.setText("Town");
    }

public void setName(String name){       
        nameLabel.setText(name);
    }    
}

MainScreen.fxml:

 <?xml version="1.0" encoding="UTF-8"?>

    <?import java.lang.*?>
    <?import java.net.*?>
    <?import java.util.*?>
    <?import javafx.scene.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.effect.*?>
    <?import javafx.scene.image.*?>
    <?import javafx.scene.layout.*?>
    <?import javafx.scene.text.*?>

    <AnchorPane id="AnchorPane" prefHeight="629.0" prefWidth="600.0" snapToPixel="true" style="-fx-background-color:  beige;" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.InterfaceHandler">
      <children>            
        <Button fx:id="button1" layoutX="512.0" layoutY="381.0" minWidth="14.0" mnemonicParsing="false" onAction="#handleButton" prefHeight="30.0" prefWidth="51.0" text="Town" visible="true" />        

        <Label fx:id="nameLabel" layoutX="57.0" layoutY="8.0" prefWidth="216.0" text="blank" />
        <Label fx:id="locationLabel" layoutX="68.0" layoutY="27.0" prefWidth="193.0" text="blank" />
      </children>
    </AnchorPane>

Solution

  • It's because you didn't properly inject your Labels from FXML file.

    Annotate your Label vars. with FXML annotation:

    public class InterfaceHandler implements Initializable {
        @FXML
        public Label nameLabel;
        @FXML
        public Label locationLabel;    
    
        public void handleButton(ActionEvent event) throws IOException {        
            locationLabel.setText("Town");
        }
    
        public void setName(String name){       
            nameLabel.setText(name);
        }    
    }
    

    Also, InterfaceHandler is a controller which you reference with fx:controller in your FXML. This instructs the FXMLLoader to create a new instance of the InterfaceHandler when the loader loads its FXML. So don't create a new InterfaceHandler in your Player class, instead make InterfaceHandler a constructor parameter for Player and use loader.getController to get the InterfaceHandler controller instance out of the FXMLLoader.

    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(getClass().getResource("MainScreen.fxml"));
    Parent root = (Parent)loader.load();
    Player player = new Player(loader.getController());
    Scene scene = new Scene(root);
    
    . . .
    
    public class Player {
      private InterfaceHandler ui;   
    
      public Player(InterfaceHandler ui) {
        this.ui = ui;
      }
    
      public void setNameLabel() {
        String name = "Dan";
        ui.setName(name);
      }
    }