JavaFX中的多个FXML / Controller的Root不能为null异常

我正在研究JavaFX项目来管理锻炼。虽然它有一个大的.fxml文件和一个大的MainController类,但它运行良好:

WorkoutsMain.fxml:

<AnchorPane id="AnchorPane" fx:id="anchorPane" prefHeight="900.0" prefWidth="1600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="workouts.WorkoutsMainController">
    <children>
        <SplitPane fx:id="splitPane" dividerPositions="0.15" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
            <items>
                <AnchorPane>
                    <children>
                        <StackPane fx:id="menuPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"/>
                    </children>
                </AnchorPane>
                <AnchorPane>
                    <children>
                        <Pane fx:id="statisticsPane" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="130.0"/>
                        <Pane fx:id="workoutsPane" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="130.0">
                        //... other FX elements
                        </Pane>
                        <Pane fx:id="calendarPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="130.0"/>
                        <StackPane fx:id="logoPane" onmouseclicked="#setLogo" AnchorPane.bottomAnchor="778.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"/>
                    </children>
                </AnchorPane>
            </items>
        </SplitPane>
    </children>
</AnchorPane>

WorkoutsMainController.java:

public class WorkoutsMainController implements Initializable,SplitPaneDividerController {
    private final DataBase dataBase = new DataBase();
    private boolean first = true;
    private String logoName;
    @FXML
    private StackPane logoPane,menuPane;
    private final List<Pane> panes = new ArrayList<>();
    @FXML
    private Pane calendarPane,workoutsPane,statisticsPane;
    @FXML
    private SplitPane splitPane;
    @FXML
    private AnchorPane anchorPane;
    // methods and functions
    @Override
    public void initialize(URL url,ResourceBundle rb) {
        setLogo();
        disableSplitPaneDivider(splitPane,0.1525);
        setUpMainmenu();
    }
}

MainClass.java:

public class MainClass extends Application {
    private Parent anchorPane;
    private final String fxml = "WorkoutsMain.fxml";
    @Override
    public void start(Stage stage) {       
        try {
            anchorPane = FXMLLoader.load(getclass().getResource(fxml));
        } catch (IOException ex) {
            System.out.println("Error when trying to load " + fxml);
          }
        Scene scene = new Scene(anchorPane);
        stage.setScene(scene);
        stage.getIcons().add(new Image(getclass().getResourceAsStream("/calendarIconWhite.png")));
        stage.setTitle("THE WORKOUT CALENDAR 1.7.0 by hazazs®");
        stage.setResizable(false);
        stage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }
}

然后我想从WorkoutsMain.fxml中切出一块。我已经在原始的.fxml大文件中更改了一段,如下所示:
来自

<Pane fx:id="workoutsPane" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="130.0">
    //... other FX elements
</Pane>

<fx:include source="Workouts.fxml" fx:id="workoutsPane"/>

然后,我用其自己的Controller类创建了一个新的fxml文件:
Workouts.fxml:

<Pane fx:id="workoutsPane" visible="false" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="130.0" xmlns:fx="http://javafx.com/fxml/1" fx:controller="workouts.WorkoutsController">
// other FX elements
</Pane>

我已经创建了一个适当的WorkoutsController类,并且已经如下更改了WorkoutsMainController:

public class WorkoutsMainController implements Initializable,SplitPaneDividerController {
    protected static final DataBase dataBase = new DataBase();
    private final WorkoutsController workoutsController = new WorkoutsController();
    private boolean first = true;
    private String logoName;
    @FXML
    private StackPane logoPane,statisticsPane;
    @FXML
    protected static SplitPane splitPane;
    @FXML
    protected static AnchorPane anchorPane;
    // and so on..

但是从现在开始,当我尝试启动我的应用程序时,我得到了异常:

Exception in Application start method
java.lang.reflect.invocationTargetException
    at sun.reflect.NativeMethodaccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodaccessorImpl.invoke(NativeMethodaccessorImpl.java:62)
    at sun.reflect.DelegatingMethodaccessorImpl.invoke(DelegatingMethodaccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
    at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
    at sun.reflect.NativeMethodaccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodaccessorImpl.invoke(NativeMethodaccessorImpl.java:62)
    at sun.reflect.DelegatingMethodaccessorImpl.invoke(DelegatingMethodaccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$159(LauncherImpl.java:182)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException: Root cannot be null
    at javafx.scene.Scene.<init>(Scene.java:336)
    at javafx.scene.Scene.<init>(Scene.java:194)
    at workouts.MainClass.start(MainClass.java:23)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$166(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$179(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$177(PlatformImpl.java:295)
    at java.security.accessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$178(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$152(WinApplication.java:177)
    ... 1 more

任何建议者,我应该怎么做才能再次进行这项工作?使用一个.fxml和一个Controller可以完美地工作。
谢谢

iCMS 回答:JavaFX中的多个FXML / Controller的Root不能为null异常

您正在WorkoutsController中创建一个新的WorkoutsMainController实例,而不是使用FXMLLoader为您创建的实例。您创建的实例中带有@FXML注释的字段都将为null,因此您可能在某处获取了null指针异常。 (您应该在控制台中看到“尝试加载WorkoutsMain.fxml时出错”消息。)因此,anchorPane方法中的start()从未初始化,并且在传递null { {1}}对anchorPane构造函数的引用。

还请注意,您(出于某些未知原因)已将ScenesplitPane anchorPane设为:这样做没有任何意义,并且static不会初始化静态领域。因此,这些字段在控制器中也为空。

如果您不压缩加载FXML引发的异常,则将能够看到底层异常的实际堆栈跟踪。

解决方法是:

  1. 不要创建带有FXMLLoader注释的字段@FXML。参见javafx 8 compatibility issues - FXML static fields

  2. 要为由static创建的包含的FXML注入实际的控制器实例,请参阅文档中的Nested Controllers。简而言之,由于您的FXMLLoader具有fx:include,因此您应该替换

    fx:id="workoutsPane"

    使用

     private final WorkoutsController workoutsController = new WorkoutsController();
    

    (并在 @FXML private WorkoutsController workoutsPaneController ; 的其余部分中将所有出现的workoutsController替换为workoutsPaneController)。

本文链接:https://www.f2er.com/1643008.html

大家都在问