0

I have my MainView class, which is the one that starts up the whole program.

public class MainView extends Application {
@Override
public void start(Stage stage) throws IOException {
    stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
        @Override
        public void handle(WindowEvent t) {
            Platform.exit();
            System.exit(0);
        }
    });

    FXMLLoader loader = new FXMLLoader(getClass().getResource("NavigationView.fxml"));
    Parent root = loader.load();
    Scene scene = new Scene(root);
    stage.setResizable(false);
    stage.setScene(scene);
    stage.show();
    stage.setTitle("Greenhouse");
}

/**
 * @param args the command line arguments
 * @throws java.sql.SQLException
 */
public static void main(String[] args) throws SQLException {
    launch(args);
}

}

This class loads my FXML and starts the program as you probably know. The controller is specified inside the FXML. Now what I want, is to be able to make a reference to this controller from any class in my program. That is because I want all my System.out.prints in every class to print out to my TextArea that is in my controller. This is the TextArea in my controller:

@FXML
private TextArea GUIprint;

So my question is, how do I make the right reference to my controller, so I can use it in all classes? I know that just making an instance of the controller in other classes would just give me a NullPointerException.

If you need to see my Initialize method in my controller, here it is, it just tells what pane to be visible at startup:

@Override
public void initialize(URL url, ResourceBundle rb) {
    loginPane.setVisible(true);

}

1 Answers1

1

You question is very unclear, because you refer to "other classes" but give absolutely no indication as to what those classes are, or where you instantiate them. I will try to answer anyway, covering all possibilities.

Since the start() method is the entry point to the entire application, the only places you can be creating any other objects are:

  1. In the controller itself, either in the initialize() method, or in an event handler
  2. In the start() method
  3. From objects you create from 1. or 2., or from objects you create from those, etc.

If you are creating those other objects in the controller itself, then you just pass a reference to them, e.g.

@FXML
private void someHandlerMethod(ActionEvent event) {
    SomeOtherClass someObject = new SomeOtherClass();
    someObject.setController(this);
    // ...
}

If you are creating those other objects in the start() method, you can get the controller instance from the FXMLLoader, and pass it to the other objects:

public void start(Stage stage) throws IOException {
    stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
        @Override
        public void handle(WindowEvent t) {
            Platform.exit();
            System.exit(0);
        }
    });

    FXMLLoader loader = new FXMLLoader(getClass().getResource("NavigationView.fxml"));
    Parent root = loader.load();

    MyController controller = loader.getController();
    SomeOtherClass someOtherObject = new SomeOtherClass();
    someOtherObject.setController(controller);

    Scene scene = new Scene(root);
    stage.setResizable(false);
    stage.setScene(scene);
    stage.show();
    stage.setTitle("Greenhouse");
}

In either case, just define the appropriate setter methods in the other class(es):

public class SomeOtherClass {

    private MyController controller ;

    public void setController(MyController controller) {
        this.controller = controller ;
    }

    // ...
}

In the third case, you can just recursively do the same thing; pass the controller reference to one object, and then pass it from that object to whoever needs it, etc.

A cleaner approach is probably to use a MVC approach, and share a model instance with all the controllers and other objects that need to modify the application state. See, perhaps, Applying MVC With JavaFx. For moderately complex applications, you might want to consider a dependency-injection framework such as afterburner.fx (which is JavaFX-specific) or Spring or Guice (which are not) to make it easier to "inject" the model where it is needed.

James_D
  • 201,275
  • 16
  • 291
  • 322
  • Thanks, I have done as you told me, I am creating the objects inside the controller class, so i did as you showed me on inside the eventhandler method. I have defined the setter method you showed in my other class (the set controller). Is the next step now to make a getter method in the controller itself to get my textarea and then just get that getter method from the instance of the controller i made in my other classes? –  Oct 26 '17 at 16:52
  • @studentjavacoder No; it's bad practice to expose UI elements outside the controller. (Suppose you decide in a few months you want to use a `ListView` instead of a `TextArea` for these logging messages, or whatever they are...) Just define a method in the controller to append text to the text area. Then you can call that method from the other classes. – James_D Oct 26 '17 at 16:55
  • like this: public void GUIprint(String s) { GUIprint.appendText(s); } –  Oct 26 '17 at 16:58
  • @studentjavacoder Well, yes (but you should give the method a sensible name). – James_D Oct 26 '17 at 16:58