liamw9
liamw9

Reputation: 566

How do you change the text in a button from another window (JavaFX + FXML)?

I am very new to using JavaFX and have having some trouble using JavaFX with FXML. I am creating a program with a "Setup" button that when clicked, opens a new window with the connection (to an Arduino) settings. On the menu is another button ("Connect") that connects to the board. This closes the window. I'm looking to have this change the text of the original "setup" button to "disconnect", however, I don't seem to be able to access the button from the "setup window". Whenever I click "connect" I get the following error:

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException

I read online that this is a wrapper for a null pointer exception. I assume that the "setup" button is null and that's why I can't change it, but I can't work out why.

Here is an excerpt from MainController.java:

   @FXML
    protected void setUpConnection(ActionEvent e) {
      SetupController setupController = new SetupController();
      setupController.init(this);
  }

The above method gets called when the "setup" button is clicked (set in the file: setupMenu.fxml). This then opens up the separate window. Here is the code in SetupController.java that opens the window:

   private void openSetupWindow() {
     try {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("setupMenu.fxml"));
        Parent root1 = (Parent)loader.load();
        Stage stage = new Stage();

        stage.setTitle("Setup Connection");
        stage.setScene(new Scene(root1));
        stage.show();
    } catch(Exception exc) {
        exc.printStackTrace();
    }
}

When the connect button is clicked, the following method (in SetupController.java) is called:

    private void changeButtonText(ConnectionEventType e) {
      Button b = main.getSetupButton();

      if(e == ConnectionEventType.CONNECT) {
        b.setText("Disconnect");
      }
      else {
        b.setText("Setup Connection...");
      }
   }

(main is the MainController object that was passed in to setupController.init() ) The above code is where I am getting the error. Just to clarify, I have 2 separate fxml files, one for the main window and one for the pop up. sample.fxml(the main window) has its controller set to MainController and is set up in Main.java (below):

    @Override
    public void start(Stage primaryStage) throws Exception{
      try {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));

        GridPane root = loader.load();

        Scene scene = new Scene(root, 1200, 900);
        scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());

        primaryStage.setTitle("Nest Control");
        primaryStage.setScene(scene);
        primaryStage.show();
      } catch (Exception e) {
        e.printStackTrace();
      }
   }

Am I trying to access the button incorrectly? Is anyone able to help? Like I said, I don't have much experience with using JavaFX or FXML.

Upvotes: 0

Views: 2157

Answers (1)

D3181
D3181

Reputation: 2102

I think the answer you are looking for is to store the controllers for each window you open so you can access the variables within the controllers, however without the rest of your code would be hard to advise you, but heres an example of what i mean:

private SetupController yourController;

@Override
public void start(Stage primaryStage) throws Exception{
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
GridPane root = loader.load();
this.yourController=loader.<SetupController>getController();
Scene scene = new Scene(root, 1200, 900);
}
}

You could then pass the variable yourController to other instances in a Model-view-controller type way and access its methods.

or something like this in your case :

  private void changeButtonText(ConnectionEventType e) {
      Button b = this.yourController.getButton(); //a method that returns your @FXML button object in your controller

      if(e == ConnectionEventType.CONNECT) {
        b.setText("Disconnect");
      }
      else {
        b.setText("Setup Connection...");
      }
   }

Or alternatively have a specific method within the controller that will set the text of the button without having to return the button object.

See the examples here and here

However please note the error you get seems to typically attributed to missing @FXML annotations so maybe make sure in this instance that you have annotated all the variables in any controllers also. See here for more details.

Upvotes: 0

Related Questions