Search code examples
javajavafxillegalargumentexception

how to switching scenes in javafx (NO FXML)


I ask for your understanding, I am a beginner;)

I'm trying to build a simple application using JavaFX. The problem is that when I open the window the first time it goes well, but if I want to change the scene it throws an error...

Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: AnchorPane@1809546[styleClass=root]is already set as root of another scene#

Main class


public class Main extends Application{

    //private Stage primaryStage;

    @Override
public void start(Stage primaryStage) {

    Login login = new Login();
    Scene scene = login.okno();



    primaryStage.setTitle("Komunikator sieciowy JAVA");
    primaryStage.setScene(scene);
    primaryStage.setResizable(false);
    primaryStage.show();

}

    //public Stage getPrimaryStage() {
    //  return this.primaryStage;
    //}

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

Login

public class Login {
    private GridPane grid;
    private Scene scene;
    private Text title;
    private Label nick;
    private Button wejdzBtn;
    private TextField userName;
    //private Alert oknoDlg;




    public Login()  {
        grid = new GridPane();
        grid.setAlignment (Pos.CENTER);
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(25,25,25,25));
        scene = new Scene (grid, 300, 150);
        utworzBtn();
        utworzLogin();
        utworzTekst();
        utworzNick();
        //oknoDialogowe();


    }

    //private void oknoDialogowe()  {
        //Alert oknoDlg = new Alert(Alert.AlertType.CONFIRMATION);
        //oknoDlg.setTitle("Informacja");
        //oknoDlg.setContentText("test");  
    //  oknoDlg.setHeaderText(null);
        //oknoDlg.showAndWait();


    //}

    private void utworzBtn() {
        wejdzBtn = new Button("Zaloguj si\u0119");
        HBox hbBtn = new HBox(10);
        hbBtn.setAlignment (Pos.BOTTOM_RIGHT);
        hbBtn.getChildren().add(wejdzBtn);
        grid.add(hbBtn, 1, 2);
        //wejdzBtn.setDisable(true);
        wejdzBtn.setOnAction(e -> {
            Messages mess = new Messages();
            grid.getScene().setRoot(mess.messa());;
        });

    }

    private void utworzLogin() {

        nick = new Label("Nick:");
        grid.add(nick, 0, 1);
    }

    private void utworzNick() {
        userName = new TextField();
        grid.add(userName,1,1);
        // informacja w polu tekstowym
        userName.setPromptText("Max 15 znak\u00f3w");
        userName.setFocusTraversable(false);

        //maksymalna ilość znaków
        final int maxLength = 15;
        userName.setOnKeyTyped(t -> {
            if (userName.getText().length() > maxLength)
            {
                int pos = userName.getCaretPosition();
                userName.setText(userName.getText(0, maxLength));
                userName.positionCaret(pos);
            }
        });

    }

    private void utworzTekst() {
        title = new Text ("Dzień dobry!");
        title.setFont(Font.font("Calibri", FontWeight.NORMAL, 20));
        grid.add(title, 0, 0, 2, 1);
    }

    public Scene okno() {
        return scene;
    }


}


and and a little another class that I'm trying to change with button from login.java

    public class Messages {
    private AnchorPane anchor;
    private Scene scena;
    //private Label nick;
    private Button sendBtn;
    private TextField poleDoWpisywania;
    private TextArea poleDoWyswietlania, pobierzNick;


    public Messages() {

        anchor = new AnchorPane();
        scena = new Scene(anchor, 700, 600);
        pobierzNick();
        poleDoWpisywania();
        poleDoWyswietlania();
        utworzPrzycisk();

}
    private void utworzPrzycisk() {
        sendBtn = new Button("Wy\u015Blij");
        sendBtn.setDisable(true);

    }

    private void pobierzNick(){
        pobierzNick = new TextArea();
        pobierzNick.setEditable(false);
        pobierzNick.setWrapText(true);
}

    private void poleDoWpisywania() {
    poleDoWpisywania = new TextField();


}

    private void poleDoWyswietlania() {
        poleDoWyswietlania = new TextArea();
        poleDoWyswietlania.setEditable(false);
        poleDoWyswietlania.setWrapText(true);


}


    public Pane messa() {
        return anchor;
}
    }

could I ask you to show the right way to fix the bug?


Solution

  • JavaFX defines a scene graph which is a tree data structure that has a single root node. For your application (i.e. the code you posted), the root node is the primaryStage (this is the parameter in method start() in class Main). The primaryStage can have several Scenes. Each Scene must have its own root node.

    The error message you are getting means that a Scene's root cannot also be the root of another Scene. In other words anchor is the root for scena in class Messages which means it can't be set as the root for scene in class Login.

    Apart from that, if you want to change Scene's you need to call method setScene() of class Stage. Here is your Login class and Messages class with changes that solve the run-time error you are getting and perform the scene change when the user clicks on wejdzBtn button.

    Login.java
    (I only changed the lambda expression in method utworzBtn().)

    public class Login {
        private GridPane grid;
        private Scene scene;
        private Text title;
        private Label nick;
        private Button wejdzBtn;
        private TextField userName;
    
        public Login()  {
            grid = new GridPane();
            grid.setAlignment(Pos.CENTER);
            grid.setHgap(10);
            grid.setVgap(10);
            grid.setPadding(new Insets(25,25,25,25));
            scene = new Scene(grid, 300, 150);
            utworzBtn();
            utworzLogin();
            utworzTekst();
            utworzNick();
        }
    
        private void utworzBtn() {
            wejdzBtn = new Button("Zaloguj si\u0119");
            HBox hbBtn = new HBox(10);
            hbBtn.setAlignment (Pos.BOTTOM_RIGHT);
            hbBtn.getChildren().add(wejdzBtn);
            grid.add(hbBtn, 1, 2);
            wejdzBtn.setOnAction(e -> {
                Messages mess = new Messages();
                Window w = scene.getWindow();
                if (w instanceof Stage) {
                    Stage s = (Stage) w;
                    s.setScene(mess.getScena());
                }
            });
        }
    
        private void utworzLogin() {
            nick = new Label("Nick:");
            grid.add(nick, 0, 1);
        }
    
        private void utworzNick() {
            userName = new TextField();
            grid.add(userName,1,1);
            userName.setPromptText("Max 15 znak\u00f3w");
            userName.setFocusTraversable(false);
    
            final int maxLength = 15;
            userName.setOnKeyTyped(t -> {
                if (userName.getText().length() > maxLength)
                {
                    int pos = userName.getCaretPosition();
                    userName.setText(userName.getText(0, maxLength));
                    userName.positionCaret(pos);
                }
            });
        }
    
        private void utworzTekst() {
            title = new Text ("Dzień dobry!");
            title.setFont(Font.font("Calibri", FontWeight.NORMAL, 20));
            grid.add(title, 0, 0, 2, 1);
        }
    
        public Scene okno() {
            return scene;
        }
    }
    

    Messages.java
    (I added method getScena().)

    public class Messages {
        private AnchorPane anchor;
        private Scene scena;
        private Button sendBtn;
        private TextField poleDoWpisywania;
        private TextArea poleDoWyswietlania, pobierzNick;
    
        public Messages() {
            anchor = new AnchorPane();
            scena = new Scene(anchor, 700, 600);
            pobierzNick();
            poleDoWpisywania();
            poleDoWyswietlania();
            utworzPrzycisk();
        }
    
        private void utworzPrzycisk() {
            sendBtn = new Button("Wy\u015Blij");
            sendBtn.setDisable(true);
        }
    
        private void pobierzNick() {
            pobierzNick = new TextArea();
            pobierzNick.setEditable(false);
            pobierzNick.setWrapText(true);
        }
    
        private void poleDoWpisywania() {
            poleDoWpisywania = new TextField();
        }
    
        private void poleDoWyswietlania() {
            poleDoWyswietlania = new TextArea();
            poleDoWyswietlania.setEditable(false);
            poleDoWyswietlania.setWrapText(true);
        }
    
        public Scene getScena() {
            return scena;
        }
    
        public Pane messa() {
            return anchor;
        }
    }