3

I am having the following problem with a program that I am currently writing, and I have searched on the internet, but I couldn't really find anything to help me understand the following problem

So inside another class I have written a method that executes this whenever the search button is clicked and the method looks like this:

public void searchButton(){
        try {
            new SearchController().display();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

And then the SearchController class looks something like this (I simplified it here):

public class SearchController {

    @FXML
    private Button cancelButton;

    @FXML
    private Label what;

    private static Stage stage;

    private static BorderPane borderPane;

    @FXML
    public void initialize(){
        what.setText("Testing"); // this woks
        cancelButton.setOnAction(e -> stage.close());
    }

    public void display() throws IOException {

        stage = new Stage();
        stage.setResizable(false);
        stage.setTitle("Product search");
        stage.initModality(Modality.APPLICATION_MODAL);
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(SearchController.class.getResource("Search.fxml"));
        borderPane = loader.load();
        Scene scene = new Scene(borderPane);
        stage.setScene(scene);
        //what.setText("Testing") and this doesn't work
        stage.showAndWait();

    }



}

Can someone please tell me why it is possible to write text on the initialize method (that method gets called after the borderPane = loader.load(); line...so why doesn't it work if I try to write on the label after that line?)

Thank you in advance

1
  • As an aside, note that your static fields are going to be a disaster if you ever end up loading the FXML file twice (and having both displayed at the same time). You don't need these at all, and they are bugs waiting to happen. You can use cancelButton.setOnAction(e -> cancelButton.getScene().getWindow().hide()); to close the window (and get rid of the stage field. If you really need the borderPane field, make it an instance variable and inject it from the fxml file (i.e. remove static and just put fx:id="borderPane" on the root element of the fxml). Commented Mar 23, 2016 at 19:53

1 Answer 1

6

The FXMLLoader creates an instance of the class specified in the fx:controller attribute of the FXML root element. It then injects the elements defined in the FXML file into the controller instance it created when the fx:id attributes match the field names. Then it calls the initialize() method on that instance.

You create an instance of the controller "by hand" with new SearchController(). This is not the same object that is created by the FXMLLoader. So now when you have loaded the fxml file you have two different instances of SearchController. So if you call what.setText(...) from the display() method, you are not calling it on the controller instance created by the FXMLLoader. Consequently, what has not been initialized in the instance on which you are calling what.setText(...), and you get a null pointer exception.

Since initialize() is invoked by the FXMLLoader on the instance it created, when you call what.setText(...) from the initialize() method, you are calling it on the instance created by the FXMLLoader, and so the FXML-injected fields for that instance have been initialized.

Additional info on this issue is provided in the answer to:

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for the explanation, I have just started JavaFX so it is not that clear to me yet. What would be a good way to open a new window then? Not just in this case, in general? Because until now I thought that I should do that by creating a new Object of the controller class.
Using the default setup, the FXMLLoader creates the controller from the fxml file, so in that setup you should never create the controller objects yourself. The code you have in the display() method is exactly the code you need to create a new window and display the content of the fxml file in it, but it just doesn't make sense to make this an instance method in the controller class; you would usually just have this code at the point in your application where you needed to create the window.
Oh I see. Thanks again, it looks like I misunderstood the concept. Just another quick question : This : SearchController a = loader.getController() doesn't create a new instance right? I think I got the concept now, thanks to you :D
Yes, that's correct: loader.getController() gives you the controller that the loader created (you need to call it after you call load(), for reasons that become obvious if you think about it a bit)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.