JavaFX getScene()在控制器的initialize方法中返回null

JavaFX getScene()在控制器的initialize方法中返回null,java,javafx-8,Java,Javafx 8,昨天我用JavaFX构建了一个小应用程序。我想在控制器类中获得应用程序的场景。我每次尝试在控制器类中获取场景时都会出错。我可以在控制器类中的按钮上设置OnKeyPressed方法,效果很好。但只有选择了按钮,它才能正常工作。。我只能在主类方法replaceSceneContent中获取场景。我已经读过了,但是我在initialize方法中调用了getScene()-方法??谢谢你的建议 主要类别: public class Main extends Application { private

昨天我用JavaFX构建了一个小应用程序。我想在控制器类中获得应用程序的场景。我每次尝试在控制器类中获取场景时都会出错。我可以在控制器类中的按钮上设置OnKeyPressed方法,效果很好。但只有选择了按钮,它才能正常工作。。我只能在主类方法replaceSceneContent中获取场景。我已经读过了,但是我在initialize方法中调用了getScene()-方法??谢谢你的建议

主要类别:

public class Main extends Application {

private Stage stage;

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 {
        MenuController menu = new MenuController();
        menu = (MenuController) replaceSceneContent("Menu.fxml");
        menu.setApp(this);
    } catch (Exception ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }
}

private Node replaceSceneContent(String fxml) throws Exception {
    FXMLLoader loader = new FXMLLoader();
    @SuppressWarnings("resource")
    InputStream in = Main.class.getResourceAsStream(fxml);
    loader.setBuilderFactory(new JavaFXBuilderFactory());
    loader.setLocation(Main.class.getResource(fxml));
    BorderPane page;
    try {
        page = (BorderPane) loader.load(in);
    } finally {
        in.close();
    }
    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);
    page.prefWidthProperty().bind(scene.widthProperty());
    page.prefHeightProperty().bind(scene.heightProperty());
    stage.setScene(scene);
    return (Node) loader.getController();
}}
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();
}}
控制器类:

public class MenuController extends BorderPane implements Initializable {

Main application;

@FXML
private Button button;

public void setApp (Main application) {
    this.application = application;
}

@Override
public void initialize(URL location, ResourceBundle resources) {
    button.getScene().setOnKeyPressed(e -> {
        switch(e.getCode()) {
        case A:
            System.out.println("A pressed!");
            break;
        default:
            break;
        }
    });
}}}
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!");
}
}

这是我的应用程序的1.1版。我向setOnKeyPressed事件处理程序添加了一个if子句。控制器初始化完成后,一个方法将布尔controllerRunning变为true。最后我删除了InputStream,它是不需要的

如果某人需要一个例子:

主要类别:

public class Main extends Application {

private Stage stage;

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 {
        MenuController menu = new MenuController();
        menu = (MenuController) replaceSceneContent("Menu.fxml");
        menu.setApp(this);
    } catch (Exception ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }
}

private Node replaceSceneContent(String fxml) throws Exception {
    FXMLLoader loader = new FXMLLoader();
    @SuppressWarnings("resource")
    InputStream in = Main.class.getResourceAsStream(fxml);
    loader.setBuilderFactory(new JavaFXBuilderFactory());
    loader.setLocation(Main.class.getResource(fxml));
    BorderPane page;
    try {
        page = (BorderPane) loader.load(in);
    } finally {
        in.close();
    }
    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);
    page.prefWidthProperty().bind(scene.widthProperty());
    page.prefHeightProperty().bind(scene.heightProperty());
    stage.setScene(scene);
    return (Node) loader.getController();
}}
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();
}}
控制器类:

public class MenuController extends BorderPane implements Initializable {

Main application;

@FXML
private Button button;

public void setApp (Main application) {
    this.application = application;
}

@Override
public void initialize(URL location, ResourceBundle resources) {
    button.getScene().setOnKeyPressed(e -> {
        switch(e.getCode()) {
        case A:
            System.out.println("A pressed!");
            break;
        default:
            break;
        }
    });
}}}
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!");
}
}
你能行

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 ;
}

只是一个注释:
MenuController
作为
BorderPane
(或任何其他UI类)的子类是毫无意义的。我把它留了下来,以防你在其他地方需要它,但它完全违反了MVC模式


此外,我不太清楚为什么希望
A
的关键处理程序出现在场景中,而F11的关键处理程序出现在场景的根目录中。看来这两个都应该在现场登记。但是,我还是像您在问题中一样保留了它。

调用
initialize()
方法是在调用
loader.load(…)
期间调用的,这(必然)是在FXML中定义的UI放置到场景中之前。(顺便说一句,您不应该同时设置位置和向加载器提供输入流。完全删除
中的
输入流,并使用无参数加载方法:
page=loader.load()
)1.UI放置FXML后是否调用了方法?2.我尝试使用与SceneBuilder示例中相同的代码加载FXML:,列出了不推荐使用的代码?1.否。UI放置在场景中-因此,当调用
new scene(第页)时,按钮的
scene
属性变为非空
。控制器对场景一无所知,因此如果希望在场景中使用事件处理程序,则应在创建场景的方法中注册它。将来我将使用fxml文件创建一些附加控制器。replaceSceneContent方法在我的代码中返回了一个节点。我需要一个接受此返回值的类。但是hat代码与oracle示例中的代码相同。只是想要一个可用的应用程序:(您的代码看起来不错,我会使它与diff控制器兼容。谢谢!我做了两个切换语句,因为将来会有多个具有不同键盘配置的控制器。F11在任何地方都有意义,但“a”可能就在那个控制器里。这里有非常快速的支持:)