How to initialize JavaFX controllers with the same model object?

Viewed 28290

Scenario

I am creating a GUI where multiple views reference the same model object.

What I am Accustom to

In Swing, if i want all the views to reference the same model i would pass the model into the constructor.

What I am Currently Doing

In JavaFX, I am passing the model around by having a setter method in the views/controllers (menubars, split panes, tabs, ...), after each view/controller has been loaded. I find this very tacky and cumbersome. Additionally, I find it won't work because in certain situations i need the model to already exist in a controller before some of the controller widgets are initialized.

Lackluster Alternatives

(Note: I am referencing these stackoverflow questions:

  • Javafx 2.0 How-to Application.getParameters() in a Controller.java file
  • Passing Parameters JavaFX FXML
  • Multiple FXML with Controllers, share object
  • Passing parameters to a controller when loading an FXML)

  • Dependency Injection

    • I've looked at this website, http://www.zenjava.com/2011/10/23/javafx-2-0-fxml-and-spring/, and i have looked a little into google Guice, but I don't see a way of simplistically giving each JavaFX view/controller the same model object. It seemed like the injection would inject a different model for each view/controller.
  • Saving the model object as a public static variable

    • This is an option but at the moment I don't like the idea of having a public static model so open and available. Obviously, I can make it a private static variable and have getters and setters, but i don't like this idea much either.
  • Passing Parameters from Caller to Controller

    • I want each controller to load itself in its constructor, and I want each custom controller to be automatically injected into its parent controller. For example, the card overview tab loads itself like this:

      public CardOverviewTab() {
          FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("card_overview_tab.fxml"));
          fxmlLoader.setRoot(content);
          fxmlLoader.setController(this);
      
          try {
              fxmlLoader.load();
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
      
    • And the SingleGameSetup controller has the card overview tab automatically injected into a variable:

      public class SingleGameSetupController extends AnchorPane {
      
          @FXML private CardOverviewTab cardOverviewTab;
      
          // Rest of the class
      }
      
    • And the part of the fxml containing the card overview tab looks like this:

      <CardOverviewTab fx:id="cardOverviewTab" />
      
    • This way I do not need to worry about manually loading a controller, but I still have the problem of setting the model.

  • Setting a Controller on the FXMLLoader

    • This option is similar to what I am accustom to, passing the model as a parameter into the constructor, but it still has the problem of loading controllers manually with the FXMLLoader.
  • Event Bus

    • I haven't read too much into this, but from what I have read the event bus seems to be inactive and outdated.
  • Singleton

    • This is similar to having a public static reference to the model object that controllers can retrieve, but again I am looking for a better solution. Plus, I do not want a singleton model.

What I am Looking for

Is there a way to pass the model object around in a less cumbersome way? I am looking for a way that is as simple as passing the model to a constructor, but I do not want to deal with manually loading controllers via the FXMLLoader, or setting the model after the controllers are loaded. Maybe having a class to retrieve the model is the best option, but I am asking just in case there is a better way.

3 Answers
Related