Search code examples
javafxnetbeansnullpointerexceptionfxml

NullPointerException passing a string from a window to another


Long story short, I searched for similar problems to mine, so I could troubleshoot this "by my own". I found these examples here and here, but none of them worked for me.

I need to pass to the next window a string that was typed in the TextField of the first window.

My main:

public class Main extends Application{

    /**
     * @param stage
     * @throws java.lang.Exception
     */
     @Override
     public void start(Stage stage) throws Exception {

        FXMLLoader floader = new FXMLLoader();        
        Parent root = FXMLLoader.load(getClass().getResource("java1.fxml"));
        Java1Controller j1 = (Java1Controller)floader.getController();

        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.setResizable(false);
        stage.show();

    }


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

As I'm using FXML, here's the controller of Window1 (java1):

    public class Java1Controller implements Initializable {

    @FXML
    private TextField tSend;
    @FXML
    private Button bSend; 


    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    

    @FXML
    private void sendText(ActionEvent event) throws IOException {

        FXMLLoader fLd = new FXMLLoader();       

        Parent novo = FXMLLoader.load(getClass().getResource("java2.fxml"));       

        Java2Controller j2 = (Java2Controller)fLd.getController();
        j2.setLbText(tSend.getText());

        Scene novScene = new Scene(novo);     

        Stage novStage = (Stage)((Node)(event.getSource())).getScene().getWindow();                
        novStage.setScene(novScene);
        novStage.setResizable(false);

        novStage.show();
    }  



}

And the controller of Window2 (java2):

    public class Java2Controller implements Initializable {

    @FXML
    private Label lbText;
    @FXML
    private Button bOK;

    /**
     * Initializes the controller class.
     * @param url
     * @param rb
     */

    /**
     * @param string the string to set
     */
    public void setLbText(String string) {
        lbText.setText(string);
    }

    @FXML
    private void closeJPane(ActionEvent event) {

        Stage stage = (Stage)((Node)(event.getSource())).getScene().getWindow();
        stage.close();
    }

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


}

The problem is pointed to the Java1Controller line where I setText with my custom function (j2.setLbText). Why? If it matters, I'm using Netbeans 8.2 and JavaFX Scene Builder 11.0.

FXML Java1:

<Pane maxHeight="252.0" maxWidth="388.0" minHeight="252.0" minWidth="388.0" prefHeight="252.0" prefWidth="388.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.Java1Controller">
   <children>
      <Label layoutX="126.0" layoutY="76.0" text="Insira texto aqui:">
         <font>
            <Font size="16.0" />
         </font>
      </Label>
      <TextField fx:id="tSend" layoutX="109.0" layoutY="102.0" />
      <Button fx:id="bSend" layoutX="169.0" layoutY="178.0" mnemonicParsing="false" onAction="#sendText" text="Send" />
   </children>
</Pane>

FXML Java2:

<Pane maxHeight="388.0" maxWidth="252.0" minHeight="252.0" minWidth="388.0" prefHeight="252.0" prefWidth="388.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.Java2Controller">
   <children>
      <Label fx:id="lbText" layoutX="137.0" layoutY="106.0" text="Texto enviado">
         <font>
            <Font size="16.0" />
         </font>
      </Label>
      <Button fx:id="bOK" layoutX="164.0" layoutY="178.0" mnemonicParsing="false" onAction="#closeJPane" prefHeight="26.0" prefWidth="61.0" text="OK" />
   </children>
</Pane>

Solution

  • You're using static load methods to load the fxmls. This way a new FXMLLoader instance is created by the method that you cannot get a reference to. The FXMLLoader instance you create yourself is never used to load an fxml file, so no controller is available via its getController property:

    // here you create a loader without setting a location
    FXMLLoader fLd = new FXMLLoader();       
    // here a static method uses another loader instance to load the fxml
    Parent novo = FXMLLoader.load(getClass().getResource("java2.fxml"));       
    // here you try to retrieve the controller from the loader instance that is still in the same state as after the constructor completion
    Java2Controller j2 = (Java2Controller)fLd.getController();
    

    Change your code an use the loader instance you created yourself to load the fxml:

    // create loader with location set
    FXMLLoader fLd = new FXMLLoader(getClass().getResource("java2.fxml"));
    
    // use loader instance to load fxml from location specified
    Parent novo = fLd.load();
    
    // the controller should now be available
    Java2Controller j2 = (Java2Controller)fLd.getController();
    
    assert j2 != null