HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

JavaFX FXML/window switcher

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
switcherfxmlwindowjavafx

Problem

I would like to write simple application where I'm going to make a few views:

  • Login



  • Register



  • Main app



I think that my method is not the best way to do this. Can someone give me a tip?

Main.java

package application;

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.fxml.FXMLLoader;

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("Login.fxml"));
            Scene scene = new Scene(root,400,400);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}


Controller.java

```
package application;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class Controller implements Initializable{

@FXML
Button openRegister;

@FXML
Button openLogin;

private Stage stage;

@Override
public void initialize(URL location, ResourceBundle resources) {

}

@FXML
private void openRegister() throws IOException{
stage = (Stage) openRegister.getScene().getWindow();
BorderPane root;
root = (BorderPane) FXMLLoader.load(getClass().getResource("Register.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
stage.setScene(scene);
System.out.printl

Solution

I think you are on the right track, there are only a few things I would change.

  • I would create a static function in the controller which inflates and returns a root node to be added to the stage (or even launches a new stage).



  • I would make a separate controller for each window/fragment you want to create. So you would have a LoginController and a RegisterController, each inflating and binding to their respective fxml files.



Depending on how your app is going to to be structured, you'll likely want a MainController which provides a container to swap sub-controllers in and out of. In this way, each controller is a single entity that can be used ad-hoc; only the main controller will be aware of their existence and be responsible for displaying them. MainController would also provide the ideal place for global menus, titles, toolbar, tabs, etc.

UPDATE

public static LoginUiController initScene(Stage stage) throws IOException
{
    LoginUiController controller = new LoginUiController();

    // Inflate FXML
    FXMLLoader loader = new FXMLLoader(LoginUiController.class.getResource("controller/login/Login.fxml"));
    loader.setController(controller);
    controller.root = loader.load(); // Good to have a pointer to the root node so the controller can be nested

    // Create scene             
    Scene scene = new Scene(controller.root);                                    
    stage.setScene(scene);
    controller.onCreated(); // Method to let the controller know it has been inflated and added to a scene

    return controller;
}


I generally make use of an abstract base controller that exposes the different methods I use (inflateFxml, initScene, onCreate) as well as a property binder lookup table, so the controller can unbind all listeners when closed.

Code Snippets

public static LoginUiController initScene(Stage stage) throws IOException
{
    LoginUiController controller = new LoginUiController();

    // Inflate FXML
    FXMLLoader loader = new FXMLLoader(LoginUiController.class.getResource("controller/login/Login.fxml"));
    loader.setController(controller);
    controller.root = loader.load(); // Good to have a pointer to the root node so the controller can be nested

    // Create scene             
    Scene scene = new Scene(controller.root);                                    
    stage.setScene(scene);
    controller.onCreated(); // Method to let the controller know it has been inflated and added to a scene

    return controller;
}

Context

StackExchange Code Review Q#119418, answer score: 4

Revisions (0)

No revisions yet.