You can just register a listener with the list view's selection model, and load the corresponding view when the selection changes.
E.g., supposing you have
public class View {
private final String name ;
private final Class<?> controllerType ;
// You could assume that the resource is name+".fxml" if you want to rely on conventions like that
// That would eliminate the need for another field here, but would prevent
// e.g. names with whitespace etc.
private final String resource ;
public View(String name, Class<?> controllerType, String resource) {
this.name = name ;
this.controllerType = controllerType ;
this.resource = resource ;
}
public String getName() {
return name ;
}
public Class<?> getControllerType() {
return controllerType ;
}
public String getResource() {
return resource ;
}
@Override
public String toString() {
return name ;
}
}
Then in FXML:
<!-- imports, namespaces omitted -->
<BorderPane fx:id="root" fx:controller="app.MainController" ... >
<left>
<ListView fx:id="selector"/>
</left>
</BorderPane>
and in the controller:
package app ;
public class MainController {
@FXML
private BorderPane root ;
@FXML
private ListView<View> selector ;
public void initialize() {
selector.getSelectionModel().selectedItemProperty().addListener((obs, oldView, newView) -> {
if (newView == null) {
root.setCenter(null);
} else {
// assumes each FXML is in the same package as its controller
// (which I think is a nice way to organize things)
FXMLLoader loader = new FXMLLoader(newView.getControllerType().getResource(newView.getResource()));
try {
root.setCenter(loader.load());
} catch (IOException exc) {
// unrecoverable...
throw new UncheckedIOException(exc);
}
}
});
selector.getItems().addAll(
new View("Fruits", FruitsController.class, "Fruits.fxml"),
new View("Vegetables", VegetablesController.class, "Vegetables.fxml")
);
}
}
If all the controllers have common functionality, you can make them implement a common interface (ProductsController
, for example), and retrieve the current controller from the loader with ProductsController currentController = loader.getController();
after loading the new FXML. (You can also change the type of controllerType
in View
to Class<? extends ProductsController>
in this case.)