JavaFX getScene() returns null in initialize method of the controller

后端 未结 2 539
傲寒
傲寒 2020-12-21 17:53

I built a small application in JavaFX yesterday. I wanted to get the Scene of the application in the Controller class. I got an error every time I tried to get the scene in

相关标签:
2条回答
  • 2020-12-21 18:32

    Here's version 1.1 from my app. I added an if-clause to the setOnKeyPressed event handler. After the initialization of the controller is complete, a method turns the boolean controllerRunning to true. Finally I removed the InputStream, it's not needed.

    If somebody needs an example:

    Main class:

    public class Main extends Application {
    
    private Stage stage;
    private boolean controllerRunning = false;
    MenuController menu;
    
    public void setControllerRunning(boolean controllerRunning) {
        this.controllerRunning = controllerRunning;
    }
    
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) throws Exception {
        stage = primaryStage;
        gotoMenu();
        primaryStage.show();
    }
    
    public void gotoMenu() {
        try {
            menu = new MenuController();
            menu = (MenuController) replaceSceneContent("Menu.fxml");
            menu.setApp(this);
            menu.keyFunctions();
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    private Node replaceSceneContent(String fxml) throws Exception {
        FXMLLoader loader = new FXMLLoader();
        loader.setBuilderFactory(new JavaFXBuilderFactory());
        loader.setLocation(Main.class.getResource(fxml));
        BorderPane page;
        try {
            page = (BorderPane) loader.load();
        } finally {
        }
        page.setOnKeyPressed(event -> {
            if (controllerRunning) {
                switch (event.getCode()) {
                case A:
                    menu.printA();
                    break;
                default:
                    break;
                }
            }
            switch (event.getCode()) {
            case F11:
                if (stage.isFullScreen()) {
                    stage.setFullScreen(false);
                } else {
                    stage.setFullScreen(true);
                }
                break;
            default:
                break;
            }
        });
        Scene scene = new Scene(page);
        page.prefWidthProperty().bind(scene.widthProperty());
        page.prefHeightProperty().bind(scene.heightProperty());
        stage.setScene(scene);
        return (Node) loader.getController();
    }}
    

    controller class:

    public class MenuController extends BorderPane{
    
    Main application;
    
    @FXML
    private Button button;
    
    public void setApp (Main application) {
        this.application = application;
    }
    
    public void keyFunctions() {
        application.setControllerRunning(true);
    }
    public void printA() {
        System.out.println("A!");
    }
    }
    
    0 讨论(0)
  • 2020-12-21 18:53

    You can do

    private Node replaceSceneContent(String fxml) throws Exception {
        FXMLLoader loader = new FXMLLoader();
        loader.setBuilderFactory(new JavaFXBuilderFactory());
        loader.setLocation(Main.class.getResource(fxml));
    
        BorderPane page = loader.load();
        MenuController controller = loader.getController();
    
        page.setOnKeyPressed(event -> {
            switch (event.getCode()) {
            case F11:
                if (stage.isFullScreen()) {
                    stage.setFullScreen(false);
                } else {
                    stage.setFullScreen(true);
                }
                break;
            default:
                break;
            }
        });
        Scene scene = new Scene(page);
        scene.setOnKeyPressed(event -> {
            if (event.getCode() == KeyCode.A) {
                controller.printA();
            }
        });
    
    
        page.prefWidthProperty().bind(scene.widthProperty());
        page.prefHeightProperty().bind(scene.heightProperty());
        stage.setScene(scene);
        return controller ;
    }
    

    with

    public class MenuController extends BorderPane{
    
        // existing code...
    
        public void printA() {
            System.out.println("A!");
        }
    
    }
    

    Just a comment: it makes absolutely no sense for MenuController to be a subclass of BorderPane (or any other UI class). I left that in, in case you need it elsewhere, but it completely violates the MVC pattern.

    Additionally, I'm not really sure why you want the key handler for A to be on the scene, and the key handler for F11 to be on the root of the scene. It seems these should both be registered with the scene. But again, I left it as you had it in the question.

    0 讨论(0)
提交回复
热议问题