简体   繁体   中英

How to swtich to new scene in the same stage JavaFX

I try to switch between scenes in same stage. I'm beginner in JavaFX so I don't know how to do it easily without spaghetti code. When I start code below I get null pointer at rootLayout.setCenter(content) in showCarChoosePage method (second scene). I know rootLayout is null and I was trying create new scene with and load it to primaryStage but then I got null pointer too. showCarChoosePage method is calling from LoginController. Thanks for your help

public class MC extends Application {
    public Scene scene;
    private GridPane grid;
    public AnchorPane content;
    public BorderPane rootLayout;
    public Stage primaryStage;

@Override
public void start(Stage primaryStage) {

    this.primaryStage = primaryStage;
    this.primaryStage.setTitle("VMHT v0.1");

    try {
        FXMLLoader loader = new FXMLLoader(MC.class.getResource("view/RootLayout.fxml"));
        rootLayout = (BorderPane) loader.load();
        Scene scene = new Scene(rootLayout);
        primaryStage.setScene(scene);
        primaryStage.show();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    showLoginPage();
    //showCarChoosePage();

}
public void showLoginPage(){

    try {
        FXMLLoader loader = new FXMLLoader(MC.class.getResource("view/LoginView.fxml"));
        content = (AnchorPane) loader.load();
        rootLayout.setCenter(content);

        LoginController controller = loader.getController();
        controller.setMC(this);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }  
}

public void showCarChoosePage(){

    try {
        FXMLLoader loader = new FXMLLoader(MC.class.getResource("view/CarChooseView.fxml"));
        AnchorPane content = (AnchorPane) loader.load();
        rootLayout.setCenter(content);

        CarChooseController controller = loader.getController();
        controller.setMC(this); 
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }  

}

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

}

Here is another way to handle multiple scenes. It uses Controllers for each scene. You must pass the initial stage that was created in Main to each new Controller. You must also pass whatever data you want to share from Controller to Controller. This is all done with methods that are added to your controllers.

In this simple case a Person object was created with name, sex, and age class variables as well as setters and getters for these objects.

Then I created 3 fxml files (using SceneBuilder) that displayed the name, sex, and age values. Of course, I also created 3 controllers, one for each fxml file.

The user was allowed to edit these values. One scene allowed name entry, another allowed sex entry, and the last allowed age entry. This simulated a complex app where data entry and processing was divided among 3 different scenes.

The three fxml files and the 3 controllers look very similar to one another. Here is the NameController. It first has setters for the Stage and Person objects. It also has button event handlers to allow the user to navigate to the other stages.

package multiscene;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

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

public class NameController implements Initializable {

    @FXML private TextField lblSex;
    @FXML private TextField lblAge;
    @FXML private TextField txtName;
    private Stage myStage;
    private Person person;

    public void setStage(Stage myStage) {
        this.myStage = myStage;
    }

    public void setPerson(Person person) {
        this.person = person;
        lblAge.setText(person.getAge());
        txtName.setText(person.getName());
        lblSex.setText(person.getSex());
    }

    @FXML
    private void ageClicked(ActionEvent event) throws Exception{
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(NameController.class.getResource("Age.fxml"));
        AnchorPane page = (AnchorPane) loader.load();
        Stage dialogStage = new Stage();
        dialogStage.setTitle("Person Editor");
        // dialogStage.initModality(Modality.WINDOW_MODAL);
        //dialogStage.initOwner(primaryStage);
        Scene scene = new Scene(page);
        dialogStage.setScene(scene);

        // Set the person into the controller
        person.setName(txtName.getText());
        AgeController newController = loader.getController();
        newController.setStage(dialogStage);
        newController.setPerson(person);
        dialogStage.show();
        myStage.close();
    }

    @FXML
    private void sexClicked(ActionEvent event) throws Exception {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(AgeController.class.getResource("Sex.fxml"));
        AnchorPane page = (AnchorPane) loader.load();
        Stage dialogStage = new Stage();
        dialogStage.setTitle("Person Editor");
        // dialogStage.initModality(Modality.WINDOW_MODAL);
        //dialogStage.initOwner(primaryStage);
        Scene scene = new Scene(page);
        dialogStage.setScene(scene);

        // Set the person into the controller
        person.setName(txtName.getText());
        SexController newController = loader.getController();
        newController.setStage(dialogStage);
        newController.setPerson(person);
        dialogStage.show();
        myStage.close();
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }

}  

Main.java must initialize the Stage and the shared data as follows. Both the Stage and the shared data are passed to the first Scene when it is loaded.

package multiscene;

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

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Person person = new Person();
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Main.class.getResource("Name.fxml"));
        AnchorPane page = (AnchorPane) loader.load();
        Stage dialogStage = new Stage();
        dialogStage.setTitle("Person Editor");
        Scene scene = new Scene(page);
        dialogStage.setScene(scene);
        NameController nameController = loader.getController();
        nameController.setStage(dialogStage);
        nameController.setPerson(person);
        dialogStage.show();
    }

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

Here is one simple method you might try

import javafx.stage.Stage;

public class ManyScenes extends Application {

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    Application.launch(args);
}

@Override
public void start(final Stage primaryStage) {
    primaryStage.setTitle("Hello World");

    Group root1 = new Group();
    Group root2 = new Group();
    Group root3 = new Group();

    final Scene scene1 = new Scene(root1, 300, 250);
    final Scene scene2 = new Scene(root2, 300, 250);
    final Scene scene3 = new Scene(root3, 300, 250);

    Button go1 = new Button();
    go1.setLayoutX(100);
    go1.setLayoutY(80);
    go1.setText("Go  to scene2");
    go1.setOnAction(new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
            primaryStage.setScene(scene2);
        }
    });
    root1.getChildren().addAll(new Label("Scene 1"), go1);

    Button go2 = new Button();
    go2.setLayoutX(100);
    go2.setLayoutY(80);
    go2.setText("Go to scene3");
    go2.setOnAction(new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
            primaryStage.setScene(scene3);
        }
    });

    root2.getChildren().addAll(new TextField(), go2);

    Button go3 = new Button();
    go3.setLayoutX(100);
    go3.setLayoutY(80);
    go3.setText("Back to scene1");
    go3.setOnAction(new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
            primaryStage.setScene(scene1);
        }
    });

    root3.getChildren().addAll(new TextArea(), go3);

    primaryStage.setScene(scene1);
    primaryStage.show();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM