Accessing FXML controller class

Solution 1:

You can get the controller from the FXMLLoader

FXMLLoader fxmlLoader = new FXMLLoader();
Pane p = fxmlLoader.load(getClass().getResource("foo.fxml").openStream());
FooController fooController = (FooController) fxmlLoader.getController();

store it in your main stage and provide getFooController() getter method.
From other classes or stages, every time when you need to refresh the loaded "foo.fxml" page, ask it from its controller:

getFooController().updatePage(strData);

updatePage() can be something like:

// ...
@FXML private Label lblData;
// ...
public void updatePage(String data){
    lblData.setText(data);
}
// ...

in the FooController class.
This way other page users do not bother about page's internal structure like what and where Label lblData is.

Also look the https://stackoverflow.com/a/10718683/682495. In JavaFX 2.2 FXMLLoader is improved.

Solution 2:

Just to help clarify the accepted answer and maybe save a bit of time for others that are new to JavaFX:

For a JavaFX FXML Application, NetBeans will auto-generate your start method in the main class as follows:

@Override
public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

    Scene scene = new Scene(root);

    stage.setScene(scene);
    stage.show();
}

Now, all we need to do to have access to the controller class is to change the FXMLLoader load() method from the static implementation to an instantiated implementation and then we can use the instance's method to get the controller, like this:

//Static global variable for the controller (where MyController is the name of your controller class
static MyController myControllerHandle;

@Override
public void start(Stage stage) throws Exception {
    //Set up instance instead of using static load() method
    FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
    Parent root = loader.load();

    //Now we have access to getController() through the instance... don't forget the type cast
    myControllerHandle = (MyController)loader.getController();

    Scene scene = new Scene(root);

    stage.setScene(scene);
    stage.show();
}

Solution 3:

Another solution is to set the controller from your controller class, like so...

public class Controller implements javafx.fxml.Initializable {

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // Implementing the Initializable interface means that this method
        // will be called when the controller instance is created
        App.setController(this);
    }

}

This is the solution I prefer to use since the code is somewhat messy to create a fully functional FXMLLoader instance which properly handles local resources etc

@Override
public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("/sample.fxml"));
}

versus

@Override
public void start(Stage stage) throws Exception {
    URL location = getClass().getResource("/sample.fxml");
    FXMLLoader loader = createFXMLLoader(location);
    Parent root = loader.load(location.openStream());
}

public FXMLLoader createFXMLLoader(URL location) {
    return new FXMLLoader(location, null, new JavaFXBuilderFactory(), null, Charset.forName(FXMLLoader.DEFAULT_CHARSET_NAME));
}

Solution 4:

On the object's loading from the Main screen, one way to pass data that I have found and works is to use lookup and then set the data inside an invisible label that I can retrieve later from the controller class. Like this:

Parent root = FXMLLoader.load(me.getClass().getResource("Form.fxml"));
Label lblData = (Label) root.lookup("#lblData");
if (lblData!=null) lblData.setText(strData); 

This works, but there must be a better way.