Search code examples
javajavafxjavafx-8scenebuilderscene

Problems switching scenes (transitioning from one to another)


I'm writting a GUI with 2 scenes, the first one being one to connect to the server (which has been written already and works great), and the second one, the game itself.

I've looked up tutorials, but I haven't seen one so far that could also load the FXML. I've tried doing it on my own, but I was unsuccessful. I've implemented 2 separate controllers, and 2 separate FXML's, but I'm not managing to implement all of the above in the Main.java, and cannot switch scenes either with a button, my code looks like this at the moment.

Main.java

public class Main extends Application {
Stage window;
Scene scene1, scene2;

@Override
public void start(Stage primaryStage) throws Exception {
    window = primaryStage;

    Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
    primaryStage.setTitle("GUI v3.0");
    primaryStage.setScene(new Scene(root, 700, 700));
    primaryStage.getIcons().add(new Image("/sample/R_enormousRing.png"));
    primaryStage.show();

    //Stage 2
    //secondaryStage.setScene(new Scene(root, 700, 700));
    Parent secondary = FXMLLoader.load(getClass().getResource("sample2.fxml"));


    String hostName = "localhost"; // hard coded at the moment, but I'm trying to get the values from the "login" scene and use those 
    int portNumber = 2123; //idem
    Socket serverSocket = new Socket(hostName, portNumber);

Controller.java

public class Controller {


@FXML
private GridPane grid;

public void initialize() {
// useless code for now
}

Controller2.java

public class Controller2 {

//empty for now 



}

and I hope that the FXML's aren't necessary right now.

Updated code

public class Main extends Application {
@FXML
public Button button;

@Override
public void start(Stage primaryStage) throws Exception {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("SceneOneController.fxml"));
    Parent root = loader.load();
    primaryStage.setTitle("GUI v3.0");
    primaryStage.setScene(new Scene(root, 700, 700));
    primaryStage.getIcons().add(new Image("/sample/R_enormousRing.png"));
    primaryStage.show();

    //Stage 2
    //secondaryStage.setScene(new Scene(root, 700, 700));

    button.setOnMouseClicked((MouseEvent event) -> {
        FXMLLoader innerLoader = new FXMLLoader(getClass().getResource("MainController.fxml"));
        try
        {
            Stage stage = new Stage();
            Parent innerRoot = innerLoader.load();
            stage.setTitle("Scene One");
            stage.setScene(new Scene(innerRoot, 700, 700));
            stage.show();
            primaryStage.close();
        } catch (IOException e)
        {
            e.printStackTrace();
        }

    });

and errors

Exception in Application start method
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:473)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:372)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:945)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:973)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:198)
    at java.base/java.lang.Thread.run(Thread.java:844)
Caused by: java.lang.NullPointerException
    at sample.Main.start(Main.java:35)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:919)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$11(PlatformImpl.java:449)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$9(PlatformImpl.java:418)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:417)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:175)
    ... 1 more
Exception running application sample.Main

Solution

  • In this sample app, I add a Button. I set the Button to disabled. I load the Splash Screen. When the Splash Screen finish loading, I enable the Button. If the Button is clicked, it loads the first Scene.

    Main

    import java.io.IOException;
    import javafx.application.Application;
    import javafx.concurrent.Task;
    import javafx.event.Event;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.stage.Stage;
    
    public class JavaFXApplication104 extends Application
    {
    
        @Override
        public void start(Stage primaryStage) throws Exception
        {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
            Parent root = loader.load();
            FXMLDocumentController mainController = loader.getController();
    
            primaryStage.setTitle("Hello World");
            primaryStage.setScene(new Scene(root, 300, 275));
            primaryStage.show();
    
            Button button = mainController.getButton();
            button.setOnAction(event -> {
                FXMLLoader innerLoader = new FXMLLoader(getClass().getResource("SceneOne.fxml"));
                try {
    
                    Stage stage = new Stage();
                    Parent innerRoot = innerLoader.load();
                    stage.setTitle("Scene One");
                    stage.setScene(new Scene(innerRoot, 500, 500));
                    stage.show();
                    primaryStage.close();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            });
            button.setDisable(true);
    
            final Task task = new Task<Void>()
            {
                @Override
                protected Void call() throws Exception
                {
                    for (int i = 1; i < 100000000; i++) {
                        updateProgress(i, 100000000);
                    }
    
                    return null;
                }
            };
    
            task.setOnSucceeded((Event event) -> {
                button.setDisable(false);
            });
    
            mainController.getPBSplashValue().progressProperty().bind(task.progressProperty());
            mainController.getPISplash().progressProperty().bind(task.progressProperty());
    
            new Thread(task).start();
    
        }
    
        public static void main(String[] args)
        {
            launch(args);
        }
    }
    

    1st Controller

    import java.net.URL;
    import java.util.ResourceBundle;
    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.scene.control.Button;
    import javafx.scene.control.ProgressBar;
    import javafx.scene.control.ProgressIndicator;
    
    /**
     *
     * @author blj0011
     */
    public class FXMLDocumentController implements Initializable
    {
    
        @FXML
        ProgressBar pbSplash;
        @FXML
        ProgressIndicator piSplash;
    
        @FXML
        Button button;
    
        public ProgressBar getPBSplashValue()
        {
            return pbSplash;
        }
    
        public ProgressIndicator getPISplash()
        {
            return piSplash;
        }
    
        public Button getButton()
        {
            return button;
        }
    
        @Override
        public void initialize(URL location, ResourceBundle resources)
        {
    
        }
    }
    

    1st FXML

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.control.Button?>
    <?import javafx.scene.control.ProgressBar?>
    <?import javafx.scene.control.ProgressIndicator?>
    <?import javafx.scene.layout.StackPane?>
    <?import javafx.scene.layout.VBox?>
    
    <StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication104.FXMLDocumentController">
        <children>
          <VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0">
             <children>
                  <VBox maxHeight="-Infinity" maxWidth="-Infinity">
                      <children>
                          <ProgressBar fx:id="pbSplash" prefWidth="200.0" progress="0.0" />
                          <ProgressIndicator fx:id="piSplash" progress="0.0" />
                      </children>
                  </VBox>
                <Button fx:id="button" mnemonicParsing="false" text="Button" />
             </children>
          </VBox>
        </children>
    </StackPane>
    

    2nd Controller

    import java.net.URL;
    import java.util.ResourceBundle;
    import javafx.fxml.Initializable;
    
    /**
     * FXML Controller class
     *
     * @author blj0011
     */
    public class SceneOneController implements Initializable
    {
    
        /**
         * Initializes the controller class.
         */
        @Override
        public void initialize(URL url, ResourceBundle rb)
        {
            // TODO
        }
    
    }
    

    2nd FXML

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import java.lang.*?>
    <?import java.util.*?>
    <?import javafx.scene.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
    
    <AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication104.SceneOneController">
    
    </AnchorPane>