Nikolas
Nikolas

Reputation: 44456

JavaFX FXML access succeed with lookup() method but not with @FXML annotation

I start exploring the JavaFX FXML application technology.

I use one main Stage accessed in Main class with Main.getStage() that is invoked in the start of application with the overriden method public void start(Stage stage). Having two public static Scene inside to keep the persistence while switching them.

@Override
public void start(Stage stage) throws Exception {
    STAGE = stage;
    LOGIN = new Scene(FXMLLoader.load(getClass().getResource("Login.fxml")));
    REGISTER = new Scene(FXMLLoader.load(getClass().getResource("Register.fxml")));

    STAGE.setScene(LOGIN);
    STAGE.setTitle("FXApplication");
    STAGE.show();
}

public static Stage getStage() {
    return STAGE;
}

Both Scenes have the same controller class called MainController. Using:

and both having the same onClick event handleButtonAction(ActionEvent event). The TextFields are fields for a username to log in/register.

@FXML private Button buttonLoginRegister;
@FXML private Button buttonRegisterBack;
@FXML private TextField fieldLoginUsername;
@FXML private TextField fieldRegisterUsername;

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

    Stage stage = Main.getStage();

    if (event.getSource() == buttonLoginRegister) {     
        stage.setScene(Main.REGISTER);
        stage.show();

        // Setting the text, the working way
        TextField node = (TextField) stage.getScene().lookup("#fieldRegisterUsername");
        node.setText(fieldLoginUsername.getText());

        // Setting the text, the erroneous way
        // fieldRegisterUsername.setText(fieldLoginUsername.getText());

    } else {
        stage.setScene(Main.LOGIN);
        stage.show();
    }
}

My goal is to copy the value from the LOGIN TextField to the one in the REGISTER scene. It works well using the code above. However firstly I tried to access the element in the another Scene with:

fieldRegisterUsername.setText(fieldLoginUsername.getText());

And it's erroneous. To be exact, the fieldRegisterUsername is null.

Why are some elements found with the lookup(String id) method and not with @FXML annotation?

Upvotes: 0

Views: 740

Answers (1)

Itai
Itai

Reputation: 6911

As mentioned in my comment, sharing a controller between different views is rarely a good idea, and I'd strongly advise you to make a separate controller for each view.

As to your problem itself - you have two instances of your controller class, one for each time you call FXMLLoader.load. Presumably, one view has the fieldLoginUsername TextField, while the other has fieldRegisterUsername.
If the condition of the if statement is met, it means the active scene was the Login scene, thus the controller handling it is the one which has fieldLoginUsername, so naturally fieldRegisterUsername will be null.

But on the first line inside the if clause you change the active scene to the Register one, so by the time you call scene#lookup you are referring to the scene whose controller is the Register controller, the one that does have fieldRegisterUsername.

If you were to call scene#lookup before changing the active scene you would find it returns null as well.

If you must use the same class for controller, you probably want to make sure you only have one instance of that class. That would necessitate using FXMLLoader#setController.

Upvotes: 2

Related Questions