Issue
I'm working on a JavaFX project to manage workouts. While it had one big .fxml file, and one big MainController class, it worked fine:
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);
}
}
Then I wanted to cut a piece from the WorkoutsMain.fxml. I have changed a segment in the original big .fxml file like this:
from
<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>
to
<fx:include source="Workouts.fxml" fx:id="workoutsPane"/>
Then I have created a new fxml file with its own Controller class:
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>
I have created an appropriate WorkoutsController class and I have changed my WorkoutsMainController like this:
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, menuPane;
private final List<Pane> panes = new ArrayList<>();
@FXML
private Pane calendarPane, workoutsPane, statisticsPane;
@FXML
protected static SplitPane splitPane;
@FXML
protected static AnchorPane anchorPane;
// and so on..
But from now I get Exception when I try to start my application:
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
Any suggestion guys, what should I do to make this work once again? With one .fxml and one Controller it worked perfectly.
Thanks
Solution
You're creating a new WorkoutsController
instance in your WorkoutsMainController
, instead of using the one created for you by the FXMLLoader
. The @FXML
-annotated fields in the instance you create will all be null, so you are probably getting a null pointer exception somewhere. (You should be seeing the "Error when trying to load WorkoutsMain.fxml" message in the console.) Thus anchorPane
in your start()
method is never initialized and you get an exception when you pass the null anchorPane
reference to the Scene
constructor.
Note also you have (for some unknown reason) made splitPane
and anchorPane
static
: it makes no sense to do that, and the FXMLLoader
will not initialize static fields. So those fields are also null in the controller.
If you don't squash exceptions thrown by loading the FXML, you will be able to see the actual stack trace for the underlying exception.
The fixes are:
don't make
@FXML
-annotated fieldsstatic
. See javafx 8 compatibility issues - FXML static fieldsTo inject the actual controller instance for the included FXML that is created by the
FXMLLoader
, see Nested Controllers in the documentation. In short, since yourfx:include
hasfx:id="workoutsPane"
, you should replaceprivate final WorkoutsController workoutsController = new WorkoutsController();
with
@FXML private WorkoutsController workoutsPaneController ;
(and replace all occurrences of
workoutsController
withworkoutsPaneController
in the remainder ofWorkoutsMainController
).
Answered By - James_D