Sunquyman
Sunquyman

Reputation: 23

JavaFX Project breaks when exported to runnable .jar? FXMLLoader related?

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

Answers (2)

GOXR3PLUS
GOXR3PLUS

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

enter image description here

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.

enter image description here

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

Diego Moraes
Diego Moraes

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

Related Questions