Abdullah Asendar Abdullah Asendar - 6 months ago 187
Java Question

JavaFX SceneBuilder 2 relative path exception

i am building a javaFX app using SceneBuilder, the problem is, when i specify a relative path in the fxml file, it throws an exception on runtime:

null/../images/text_formal.png
javafx.fxml.LoadException:
unknown path:13

at javafx.fxml.FXMLLoader.constructLoadException(Unknown Source)
at javafx.fxml.FXMLLoader.loadImpl(Unknown Source)
at javafx.fxml.FXMLLoader.load(Unknown Source)
at com.graduation.project.fxml.manager.FXMLManager.<init>(FXMLManager.java:26)
at com.graduation.project.Main.start(Main.java:14)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$163(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$176(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$174(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$175(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$149(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Caused by: java.lang.IllegalArgumentException: Invalid URL: Invalid URL or resource not found
at javafx.scene.image.Image.validateUrl(Unknown Source)
at javafx.scene.image.Image.<init>(Unknown Source)
at com.sun.javafx.fxml.builder.JavaFXImageBuilder.build(Unknown Source)
at com.sun.javafx.fxml.builder.JavaFXImageBuilder.build(Unknown Source)
at javafx.fxml.FXMLLoader$ValueElement.processEndElement(Unknown Source)
at javafx.fxml.FXMLLoader.processEndElement(Unknown Source)
... 13 more


anyhow when i set the absolute path it works fine ,, what i am doing wrong ?

my fxml :

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.image.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="427.0" prefWidth="482.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.graduation.project.main.gui.MainScreen">
<children>
<Pane layoutX="77.0" prefHeight="73.0" prefWidth="482.0" style="-fx- background-color: #5475ba;" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<ImageView fitHeight="150.0" fitWidth="200.0" layoutX="77.0" layoutY="52.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="10.0">
<image>
<Image url="@../images/text_formal.png" />
</image>
</ImageView>
</children>
</AnchorPane>


Loading the FXMl

public class FXMLManager{

FXMLLoader fxmlLoader;
Parent root;
String stageFXMLName;


public FXMLManager(String stageFXMLName){
try {

this.stageFXMLName = stageFXMLName;
this.fxmlLoader = constructFXMLLoader(stageFXMLName);
this.root = (Parent) this.fxmlLoader.load(getURL("/fxml/" + stageFXMLName).openStream());

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

private FXMLLoader constructFXMLLoader(String stageFXMLName) {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getURL(stageFXMLName));
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());

return fxmlLoader;
}


public <T> T getController(Class<T> controllerType) {

// this.root = (Parent) this.fxmlLoader.load(getURL("/fxml/" + this.stageFXMLName).openStream());

T controller = controllerType.cast(this.fxmlLoader.getController());
return controller;
}

public URL getURL(String url) {
return FXMLManager.class.getResource(url);
}


public Stage getStage(String title) {
Scene scene =new Scene(this.root);
Stage stage = new Stage();
// scene.getStylesheets().add("/styles/" + TerminalUtilsDataModel.instance.getTheme() + ".css");
stage.setScene(scene);
stage.setTitle(title);
// stage.getIcons().add(new Image("/images/stage_logo.png"));
return stage;
}

}


and calling with :

FXMLManager manager = new FXMLManager(FXMLConstants.MAIN_SCREEN);
//manager.getController(MainScreen.class).setUp();
Stage stage = manager.getStage("test");
stage.show();

Answer

When you load from a stream, FXMLLoader does not know how to resolve relative paths because there is no concept of a relative location in relation to a stream. Instead, in your FXMLManager load the FXML from a URL location that you already set on the FXMLLoader instance:

Don't do this:

this.root = (Parent) this.fxmlLoader.load(getURL("/fxml/" + stageFXMLName).openStream());

Instead, do this:

this.root = (Parent) this.fxmlLoader.load();
Comments