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.