A JavaFX Router to easily switch between scenes
- RouterFX: The router used to switch scene
- RoutedWindow: A wrapper of the JavaFX stage used by RouterFX
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'com.github.mavek87:RouterFX:1.2.9'
}
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.github.mavek87</groupId>
<artifactId>RouterFX</artifactId>
<version>1.2.9</version>
</dependency>
Wrap your stage into a RoutedWindow in the JavaFX start method
RoutedWindow window = new RoutedWindow(primaryStage);
Before using RouterFX you need to call the RouterFX.init
method first, otherwise you will receive an IllegalArgumentStateException. Usually the init method should be called in your start method after the window creation, and it takes the window as parameter.
RouterFX.init(window);
After the init is called you have to define the routes. To do it use the RouterFX.when
method. You can specify the view fxml using a string (the fxml will be searched inside src/main/resources):
RouterFX.when("view1", "view1.fxml");
Or using an URL:
RouterFX.when("view2", getClass().getClassLoader().getResource("view2.fxml");
Or passing a dumb view created programmatically without a controller:
BorderPane borderPane = new BorderPane();
Button btn = new Button("Click me!");
btn.setOnAction(actionEvent -> {
System.out.prinln("Hello console!");
});
borderPane.setCenter(btn);
RouterFX.when("view3", borderPane);
Use the method RouterFX.goTo()
everywhere you want (e.g. from your controllers) to switch scene
RouterFX.goTo("view1");
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("view.fxml"));
primaryStage.setTitle("App title");
primaryStage.setScene(new Scene(root, 640, 480));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
import javafx.application.Application;
import javafx.stage.Stage;
import com.matteoveroni.routerfx.*; // import RouterFX classes
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
// create the window wrapping the primary stage
RoutedWindow window = new RoutedWindow(primaryStage, "App title", new RoutedWindowSize(640.0, 480.0));
// init FXRouter
RouterFX.init(window);
// set a route
RouterFX.when("view", "view.fxml");
// switch to view scene
RouterFX.goTo("view");
}
public static void main(String[] args) {
launch(args);
}
}
It is possible to build a RoutedWindow
using several parameters:
Parameter name | Parameter type | Mandatory | Description |
---|---|---|---|
title | String | Yes | The title of the window |
windowSize | RoutedWindowSize | No | The size of the window (width x height) |
resizableByDefault | Boolean | No | If true the window is resizable or else not resizable |
maximizedByDefault | Boolean | No | If true the window is maximized by default or esle not maximized by default |
Parameter name | Parameter type | Mandatory | Description |
---|---|---|---|
width | double | Yes | The width of the window |
height | double | No | The height of the window |
You can create a RoutedWindow
using the constructor with the desired parameters or a builder for a more fluent API:
RoutedWindow window = RoutedWindow.builder(stage)
.title("App title")
.windowSize(new RoutedWindowSize(1024d, 768d))
.maximizedByDefault(true)
.resizableByDefault(true)
.build();
If you have some controller with not empty constructor you should pass a controller factory (Callback<Class<?>, Object> controllerFactory) to the init method. You can create the controller factory by hand or use a dependency injection framework.
RouterFX.init(window, myControllerFactory);
The goTo method is overloaded and can be called using several parameters
Parameter name | Parameter type | Mandatory | Description |
---|---|---|---|
routeId | String | Yes | The name of the route |
extraData | ExtraData | No | Data to pass to the next scene controller |
animation | RouterAnimation | No | An enum which allow to specify an animation |
windowSize | RoutedWindowSize | No | The size of the next opened scene |
You can also use the methods goBack()
and goForward()
to navigate to the previous or next visited scene. RouterFX contains internally a history object which stores each time you switch scene. The history object has a similar API to the browser History API https://developer.mozilla.org/en-US/docs/Web/API/History_API
RouterFX.goBack();
RouterFX.goForward();
If you need to pass data between two scenes (controllers) you have to pass an ExtraData
parameter in the goTo()
method.
String greeting = "Hello world!";
RouterFX.goTo("vista1", new ExtraData(greeting));
Suppose to call the goTo with extra data (our greeting) in controller1. To retrieve the extra data sent by the last goTo you have two choices:
- Method 1: From controller2 you can receive the greeting with this code:
String receivedGreeting = (String) RouterFX.getExtraData();
- Method2: Or you can implement the interface
RoutedController
in controller2
public class Controller2 implements RoutedController {
@Override
public void routedControllerReady(Optional<ExtraData> dataFromPreviousRoute) {
dataFromPreviousRoute.ifPresent(data -> System.out.println("data from previous route => " + data));
}
The RoutedController interface is used by RouteFX to inject in your controllers the extra data sent in the last RouterFX.goTo()
.
public interface RoutedController {
void routedControllerReady(Optional<ExtraData> dataFromPreviousRoute);
}
You can use both methods to retrieve the extra data because they store the same data. The only note is that you cannot call the RouterFX.getExtraData()
from the javafx initialize method, so if you need to setup something before the scene is showed for the first time you should use the RoutedController
callback aproach.
You can retrieve each of your controllers from others using the code:
MyViewController c = RouterFX.getRouteScene("myView").getController();
- Credits to Marco Trombino (https://github.com/Marcotrombino/FXRouter) for the idea. This router has more advanced functionalities but was influenced by FXRouter even though it is completely written from scratch and has conceptual differencies under the hood.
- Credits to web history API (https://developer.mozilla.org/en-US/docs/Web/API/History_API)