2

I create Pane in Scene Builder for Java 8. My .css files store in /rescouces/css/app.css. I connect stylesheet in Scene Builder and all ok. But after i start my app i get exception with error: Caused by: javafx.fxml.LoadException: Invalid resource: /../style/app.css not found on the classpath.

How to fix this? I need every time rename path to css in .fxml?

enter image description here

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="912.0" prefWidth="1368.0" styleClass="app" stylesheets="@/style/app.css" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.mypod.tablet.controller.MainController">
    <children>
        <AnchorPane fx:id="contentPane" layoutX="248.0" layoutY="138.0" stylesheets="@/style/content.css" AnchorPane.bottomAnchor="94.0" AnchorPane.leftAnchor="250.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="115.0">
            <styleClass>
                <String fx:value="block" />
                <String fx:value="content-block" />
            </styleClass>
        </AnchorPane>
    </children>
</AnchorPane>

Load fxml:

FXMLLoader loader = new FXMLLoader();

this.primaryStage.setScene(new Scene(loader.load(Util.getResource("/fxml/main.fxml"))));
Tsyklop
  • 369
  • 1
  • 9
  • 24
  • Can you edit your question and include somehow the structure of your project? At least the main folders (including resources), and also where and how do you try to load the `app.css` file? – José Pereda Nov 20 '18 at 10:44
  • @JoséPereda i updated my question. I connect `css` file in Scene Builder in `stylesheets` block. This css connection exist in fxml file. – Tsyklop Nov 20 '18 at 20:54
  • Ok, thanks, maybe you can post that bit of the FXML file as well, that would help. – José Pereda Nov 20 '18 at 20:56
  • @JoséPereda FXML wherein attached css? – Tsyklop Nov 20 '18 at 21:19
  • Just edit the FXML file and copy/paste the code relevant to the css part. – José Pereda Nov 20 '18 at 21:20
  • @JoséPereda updated – Tsyklop Nov 20 '18 at 21:26
  • When you open the FXML with Scene Builder, does the css work? As I see it, if you try to load `src/main/resources/style/app.css` into `src/main/resources/fxml/main.fxml` it will add `stylesheets="@../style/app.css"`. Note the `..` parent dots since the fxml file is inside the fxml folder, and you are setting a relative path between them. – José Pereda Nov 20 '18 at 22:20
  • @JoséPereda That is the problem) In this `..` dots. If you run application with `..` this css can be not found – Tsyklop Nov 21 '18 at 16:49
  • But if you remove them, Scene Builder fails to load the css, doesn't it? Can you post the code to show how you load this FXML file with the `FXMLLoader`? – José Pereda Nov 21 '18 at 16:58
  • @JoséPereda Yes. If i change path to `css` file ScneneBuilder not load it. I updated my question. – Tsyklop Nov 21 '18 at 17:22
  • And what `Util.getResource()` does? You have to show what you are doing, otherwise no-one will be able to figure it out. – José Pereda Nov 22 '18 at 20:15
  • @JoséPereda it return InputStream. `Util.class.getClassLoader().getResourceAsStream()` – Tsyklop Nov 23 '18 at 09:38

1 Answers1

3

The problem

In order to reproduce the issue, and based on the comments for the question, this is required:

Main class

@Override
public void start(Stage stage) throws Exception {
    FXMLLoader loader = new FXMLLoader();
    Parent root = loader.load(MainApp.class.getClassLoader().getResourceAsStream("fxml/scene.fxml"));

    Scene scene = new Scene(root);
    stage.setScene(scene);
    stage.show();
}

FXML under src/main/resources/fxml/scene.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane id="AnchorPane" stylesheets="@../styles/styles.css" prefHeight="200" prefWidth="320" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
    <children>
        <Button fx:id="button" text="Click Me!" />
    </children>
</AnchorPane>

CSS under src/main/resources/styles/styles.css

.button {
    -fx-font-size: 2em;
}

The project runs, but you get this error printed:

null/../styles/styles.css
com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
WARNING: Resource "../styles/styles.css" not found.

While manually editing the FXML file and removing the parent dots:

stylesheets="@/styles/styles.css"

seems to solve the issue and runs fine without warning, this prevents Scene Builder from finding the css file, so it shouldn't be done.

The solution

  • Using getResourceAsStream to retrieve the FXML file is not recommended, just use getResource().

This works:

FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(MainApp.class.getClassLoader().getResource("fxml/scene.fxml"));
  • Using the FXMLLoader empty constructor is not the recommended way, instead use the the static load method.

This works:

Parent root = FXMLLoader.load(MainApp.class.getClassLoader().getResource("fxml/scene.fxml"));
  • Finally, there is no need for class loader. The classloader is stream based, and it doesn't know about the class you retrieve it from and tries to locate from the package "fxml/scene.fxml". On the other hand, Class.getResource() is URL based and it looks up the resource relative to the class, so you need to set the path to the root of the project "/fxml/scene.fxml".

This is how it should be called:

Parent root = FXMLLoader.load(MainApp.class.getResource("/fxml/scene.fxml"));

Or in case you need the loader (for instance to retrieve the controller), this is also the recommended way:

FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("/fxml/scene.fxml"));
// YourController controller = (YourController) loader.getController();
Parent root = loader.load();

This post is worth reading.

José Pereda
  • 44,311
  • 7
  • 104
  • 132
  • Did you check this? Because I had problems with `getResource()` method in `jar` file? – Tsyklop Nov 23 '18 at 21:58
  • Yes, `getResource()` is the usual way. Of course, you can still use `getResourceAsStream()`, to load an Image from a file, for instance. Anyway, if you have any issue, post a new question, it is better than trying to solve it over comments. – José Pereda Nov 23 '18 at 22:19
  • 1
    Get hold of your controller after `loader.load()`, otherwise you will run into NullPointerException – hiddeneyes02 Jan 12 '20 at 13:03