Home > OS >  Switch scenes from FXML to pure JavaFX UI class
Switch scenes from FXML to pure JavaFX UI class

Time:03-17

I'm pretty new to JavaFX. I have learnt how to switch scenes between FXML files or classes purely coded in JavaFX only. My biggest challenge now is to switch between an FXML UI and another built in JavaFX or vice-versa, so I know it's possible but I just can't get it right. My code for my Application controller is:

package com.example.fxmltojavafx;

import com.sun.javafx.stage.EmbeddedWindow;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Stage;

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

public class HelloController extends Application {
    @FXML
    private Label welcomeText;


    @FXML
    private Button bt_switch;

    @FXML
    protected void onHelloButtonClick() {

        //switch scene method from fxml to pure javafx
        //bt_switch.setOnAction(e -> window.setScene(InterfaceSwitch));
        welcomeText.setText("Welcome to JavaFX Application!");
    }

    @Override
    public void start(Stage stage) throws Exception {
        bt_switch.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                bt_switch.setOnAction(e -> window.setScene(InterfaceSwitch));
            }
        });
    }
}

How do I reference the JavaFX class I want to load from a click of a fxml button? I tried window.setScene(), but it doesn't get my reference right. Of course I can't use FMXMLLoader.load().

The scene I want to load from this button is coded in this class: (The buttons coded into it are just a test)

package com.example.fxmltojavafx;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/***
 * Intefaccia puramente in JavaFX
 */
public class InterfaceSwitch extends Application {
    private Stage stage;
    @Override
    public void start(Stage stageInterface) throws Exception {
        VBox parent = new VBox();
        parent.getChildren().add(new Label("SERVER DOMINATOR : Inserisci dati"));
        //setup process
        HBox username = new HBox(new Label("username :")); //username field
        TextField usernametext = new TextField();
        username.getChildren().add(usernametext);
        parent.getChildren().add(username);

        HBox password = new HBox(new Label("password :")); //password field
        TextField passwordtext = new TextField();
        password.getChildren().add(passwordtext);
        parent.getChildren().add(password);

        HBox port = new HBox(new Label("port :")); //port field
        TextField porttext = new TextField();
        port.getChildren().add(porttext);
        parent.getChildren().add(port);

        HBox signupQuest = new HBox(new Label("Set up my game!"));
        parent.getChildren().add(signupQuest);

        Button button1 = new Button("Set up");
        parent.getChildren().add(button1);

        //Scene scene = new Scene(new Label("Server Dominator : Set up"));
        stage.setScene(new Scene(parent));
        stage.show();
    }
}

My FXML UI is basically just 2 buttons, one for "hello world" and the other is the bt_switch

My main class:

package com.example.fxmltojavafx;

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

import java.io.IOException;

public class HelloApplication extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
        Scene scene = new Scene(fxmlLoader.load(), 320, 240);
        stage.setTitle("Hello!");
        stage.setScene(scene);
        stage.show();
    }

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

It must be a simple set up issue but I can't get my head around it. How can I do it?

CodePudding user response:

The Application class represents the entire application, and specifically its lifecycle. Its purpose is to manage the startup and shutdown of the application via methods like start(), init(), and stop(). Consequently, each application should have only one Application subclass and there should only be one instance of it (which is created for you when the application is launched).

In the code you posted, HelloApplication represents the application lifecycle. HelloController is just a controller, and should not be a subclass of Application. InterfaceSwitch does not represent the application either (it just represents a UI), so it should not be a subclass of Application.

You should have something like

public class SomeUI {

    private VBox root ;

    public SomeUI() {
        root = new VBox();
        root.getChildren().add(new Label("SERVER DOMINATOR : Inserisci dati"));
        //setup process
        HBox username = new HBox(new Label("username :")); //username field
        TextField usernametext = new TextField();
        username.getChildren().add(usernametext);
        root.getChildren().add(username);

        HBox password = new HBox(new Label("password :")); //password field
        TextField passwordtext = new TextField();
        password.getChildren().add(passwordtext);
        root.getChildren().add(password);

        HBox port = new HBox(new Label("port :")); //port field
        TextField porttext = new TextField();
        port.getChildren().add(porttext);
        root.getChildren().add(port);

        HBox signupQuest = new HBox(new Label("Set up my game!"));
        root.getChildren().add(signupQuest);

        Button button1 = new Button("Set up");
        root.getChildren().add(button1);

    }

    public Parent getRoot() {
        return root ;
    }
}

Since you said your controller is a controller for an FXML file with two buttons, it needs two event handler methods (one for each button). The handler for the button which switches scenes just does so in the normal way. Obviously, the controller should not be an Application.

public class HelloController  {

   @FXML
   private Label welcomeText;


   @FXML
   protected void onHelloButtonClick() {
       welcomeText.setText("Welcome to JavaFX Application!");
   }

   @FXML
   protected void switchScenes() {
       SomeUI newScene = new SomeUI();
       Parent root = newScene.getRoot();
       welcomeText.getScene().setRoot(root);
   }

}

The FXML would look something like:

<VBox spacing="10" xmlns = "http://javafx.com/javafx/16" xmlns:fx = "http://javafx.com/fxml/1" fx:controller="com.example.HelloController">

    <Label fx:id="welcomeText" />
    <Button text="Say Hello" onAction="#onHelloButtonClick"/>
    <Button text="Switch scenes" onAction="#switchScenes" />

</VBox>
  • Related