Reputation: 23
I've been trying to export a JavaFX project as a .jar, but whenever I run it, I get a NullPointerException; supposedly, it can't find the FXML. I'm not sure how to handle this, is there something wrong with my project structure? I looked at: FXML layout not loaded when run jar outside Eclipse, but the solution didn't seem to work with me, and had a different issue.
The project is hosted at: https://github.com/Sunquyman/GameOfLife/tree/master/src
The stack trace I receive when attempting to run:
java.lang.NullPointerException: Location is required.
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3207)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
at main.Main.start(Main.java:21)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139)
at java.lang.Thread.run(Thread.java:745)
Really confused as to why this is happening; if it runs well in Eclipse, why would it break as an export?
Thanks in advance!
Upvotes: 2
Views: 2934
Reputation: 7265
First of all you have to create a resources folder like this:
To do this right click on the Project->New->Resource Folder->Name it as you want but a nice option is resources
Then i have modified your code as following here:
Main Class:
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
//You have to Load the font before using it into css!!
Font.loadFont(getClass().getResourceAsStream("/resources/fonts/8bit.ttf"), 14);
Scene scene = new Scene(new GUIController());
scene.getStylesheets().add(getClass().getResource("/view/application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("Game of Life Settings");
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
GUIController: Keep in mind than in .fxml file i used root and !default Controller so it looks now like this(used SceneBuilder).Basically doing this you can use GUIController class more than one times.
public class GUIController extends AnchorPane implements Initializable {
..........
private final String lotOn = "/music/soundfx/lensoftruth_on.mp3";
private final String lotOff = "/music/soundfx/lensoftruth_off.mp3";
.......
//Constructor
public GUIController(){
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/GUI.fxml"));
loader.setRoot(this);
loader.setController(this);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
.......
}
ABOUT CSS: And finally the in css file i modified this cause the css font is loaded into the code before added with css(check this here):
@font-face {
-fx-font-family: "8bit";
}
And Finally about /:
If you call getResource() for a class and do not prepend a /, the path is considered to be relative to the package of the class.Check this here
Are you happy? :)
Upvotes: 1
Reputation: 11
your code:
Parent root = FXMLLoader.load(getClass().getResource("../view/GUI.fxml"));
try to put GUI.fxml in the resources folder and change the code to this:
Parent root = FXMLLoader.load(getClass().getResource("GUI.fxml"));
Upvotes: 1