Search code examples
javajavafxscreenswitching

JavaFX - Buttons switch to the wrong scenes


In this program, I only use one scene, but change its root nodes.

Initially, the program displays the "Welcome" screen (welcomeRoot). But when I press the "Log in" button in there, the screen changes to the "Choose game mode" screen, even though in my code it clearly states "logInRoot".

It definitely is not that the logInRoot is initialised like gmodeRoot should be.

Here is an excerpt of the code, shortened for clarity.

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene; 
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class WhatsWrong extends Application { 
    public void start(Stage theStage) throws Exception {

        // Fields
        VBox welcomeRoot = new VBox(20);
        VBox logInRoot = new VBox(20);
        VBox signUpRoot = new VBox(20);
        VBox gmodeRoot = new VBox(20);
        VBox singleplayerRoot = new VBox(20);
        VBox multiplayerRoot = new VBox(20);
        VBox statsRoot = new VBox(20);
        String currentUser = "";


        // Welcome screen
        Label theWelcomeMessage = new Label("Welcome to the Morse code learning program");
        Label welcomeLabel = new Label("Welcome screen");
        Button logInBtn = new Button("Log in");
        logInBtn.setOnAction(e -> theStage.getScene().setRoot(logInRoot));    // correct link...
        Button signUpBtn = new Button("Sign in");
        logInBtn.setOnAction(e -> theStage.getScene().setRoot(signUpRoot));
        Button unloggedBtn = new Button("Continue unlogged");
        logInBtn.setOnAction(e -> theStage.getScene().setRoot(gmodeRoot));  
            // This button links directly to choosing the game mode.

        welcomeRoot.getChildren().addAll(theWelcomeMessage, welcomeLabel, logInBtn, signUpBtn, unloggedBtn);


        // Log in screen
        Button logInGoBackBtn = new Button(/*back arrow drawing here*/);
        logInGoBackBtn.setOnAction(e -> theStage.getScene().setRoot(welcomeRoot));
        Label logInLabel = new Label("Log in");
        TextArea logInUsernameInput = new TextArea();
        logInUsernameInput.setPromptText("Username - only letters and numbers, max length 15");
        logInUsernameInput.setId("username");
        TextArea logInPasswordInput = new TextArea();
        logInPasswordInput.setPromptText("Password - at least one letter, number and special character");
        logInPasswordInput.setId("password");
        logInPasswordInput.getText();
        Button logInConfirmBtn = new Button("Continue");
        logInConfirmBtn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                // verify, display error message if correct, save username to currentUsername if correct.
            }
        });
        Label logInUsernameError = new Label(/*x symbol here*/"Error - username taken or invalid");
        Label logInPasswordError = new Label(/*x symbol here*/"Error - password invalid");    
            // input these into the root and delete if need be

        logInRoot.getChildren().addAll(logInGoBackBtn, logInLabel, logInUsernameInput, logInPasswordInput, logInConfirmBtn);


        // Sign up screen
        // code and some pseudocode here - deleted to save space


        // Choose game mode screen
        Button gmodeGoBackBtn = new Button(/*back arrow drawing here*/);
        gmodeGoBackBtn.setOnAction(/*If logged in, display a pop-up about logging-off*/e -> theStage.getScene().setRoot(welcomeRoot));
        Label gmodeLabel = new Label("Choose the game mode");
        Button gmodeTo1PlayerBtn = new Button("Singleplayer");
        gmodeTo1PlayerBtn.setOnAction(e -> theStage.getScene().setRoot(singleplayerRoot));
        Button gmodeToMultiBtn = new Button("Multiplayer");
        gmodeToMultiBtn.setOnAction(e -> theStage.getScene().setRoot(multiplayerRoot));
        Button gmodeToStatsBtn = new Button("Statistics");
        gmodeToStatsBtn.setOnAction(e -> theStage.getScene().setRoot(statsRoot));

        gmodeRoot.getChildren().addAll(gmodeGoBackBtn, gmodeLabel, gmodeTo1PlayerBtn, gmodeToMultiBtn, gmodeToStatsBtn);


        // etc.


        // Dealing with stage
        theStage.setTitle("Morse code - educational program");
        Scene theScene = new Scene(welcomeRoot);    // Replace with logInRoot, and login screen shows up, as expected.
        theStage.setScene(theScene);
        theStage.show();
    }

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

P.S. "excerpt"; hope I made you laugh ;)


Solution

  • Here you are creating 3 buttons, but you are only setting action listeners to the logInBtn :

    Button logInBtn = new Button("Log in");
    logInBtn.setOnAction(e -> theStage.getScene().setRoot(logInRoot));
    Button signUpBtn = new Button("Sign in");
    logInBtn.setOnAction(e -> theStage.getScene().setRoot(signUpRoot));
    Button unloggedBtn = new Button("Continue unlogged");
    logInBtn.setOnAction(e -> theStage.getScene().setRoot(gmodeRoot));
    

    Adding another listener to the same button will override any previously set listener and that is why your root is set to gmodeRoot and why you see the wrong message.

    I'm guessing you want to change it to:

    Button logInBtn = new Button("Log in");
    logInBtn.setOnAction(e -> theStage.getScene().setRoot(logInRoot));
    Button signUpBtn = new Button("Sign in");
    signUpBtn.setOnAction(e -> theStage.getScene().setRoot(signUpRoot));
    Button unloggedBtn = new Button("Continue unlogged");
    unloggedBtn.setOnAction(e -> theStage.getScene().setRoot(gmodeRoot));