Reputation: 2554
I have a JavaFX project that I compile/run with Maven. This is how I load my login screen:
String path = "/org/openjfx/fxml/login.fxml";
URL url = getClass().getResource(path);
Parent root = FXMLLoader.load(url);
It runs neatly. url
is evaluated to file:/home/allan/IdeaProjects/california-maven/target/classes/org/openjfx/fxml/login.fxml
.
However, when I try to render another FXML file with this same code, I get javafx.fxml.LoadException caused by java.lang.IllegalStateException: Location is not set.
. The file's full url (passed to FXMLLoader
) is file:/home/allan/IdeaProjects/california-maven/target/classes/org/openjfx/fxml/sign-up.fxml
.
Which is odd, since both files exist on that location:
I wonder if this is a problem with sign-up.fxml
. Code below:
<?xml version="1.0" encoding="UTF-8"?>
<?import org.openjfx.components.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<ScrollPane hbarPolicy="NEVER" maxHeight="-Infinity" minHeight="-Infinity" minViewportHeight="768.0" minWidth="-Infinity" prefHeight="768.0" prefViewportWidth="768.0" prefWidth="1024.0" styleClass=".root-scroll-pane" stylesheets="@../css/index.css" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.openjfx.controllers.SignUpController">
<content>
<VBox prefHeight="1068.0" prefWidth="1024.0" styleClass="root-vbox" stylesheets="@../css/sign-up.css">
<children>
<HBox spacing="25.0">
<VBox.margin>
<Insets bottom="55.0" />
</VBox.margin>
<children>
<GoBackButton />
<Label text="Criar conta">
<font>
<Font name="System Bold" size="50.0" />
</font>
</Label>
</children>
<padding>
<Insets left="-20.0" />
</padding>
</HBox>
<FormField fx:id="nameField" fieldLabelText="Nome:" promptText="Ex: Allan">
<VBox.margin>
<Insets bottom="40.0" />
</VBox.margin>
</FormField>
<FormField fx:id="usernameField" fieldLabelText="Nome de usuário:" promptText="Ex: allan">
<VBox.margin>
<Insets bottom="40.0" />
</VBox.margin>
</FormField>
<FormField fx:id="emailField" fieldLabelText="Email:" promptText="Ex: [email protected]">
<VBox.margin>
<Insets bottom="40.0" />
</VBox.margin>
</FormField>
<FormField fx:id="passwordField" fieldLabelText="Senha:" isPasswordField="true">
<VBox.margin>
<Insets bottom="40.0" />
</VBox.margin>
</FormField>
<FormField fx:id="confirmPasswordField" fieldLabelText="Confirme sua senha:" isPasswordField="true">
<VBox.margin>
<Insets bottom="40.0" />
</VBox.margin>
</FormField>
<Button fx:id="signUpButton" mnemonicParsing="false" onAction="#signUpButtonClicked" prefHeight="60.0" prefWidth="800.0" styleClass="sign-up-button" stylesheets="@../css/sign-up.css" text="CRIAR">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Button>
</children>
<padding>
<Insets left="85.0" top="60.0" />
</padding>
</VBox>
</content>
</ScrollPane>
EDIT 1:
The login screen is loaded in Main.java
. The sign up screen is loaded by a file called NavigationService.java
, that lives inside org.openjfx.services
. This is the loading code on NavigationService:
private Scene buildScene(String routeName) {
String path = "/org/openjfx/fxml/" + routeName + ".fxml";
URL url = getClass().getResource(path);
System.out.println("Trying to load: " + url);
try {
Parent root = FXMLLoader.load(url);
Dimensions dimensions = Dimensions.getPrefferedSize(routeName);
return new Scene(root, dimensions.getWidth(), dimensions.getHeight());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
Full stack trace:
javafx.fxml.LoadException:
/home/allan/IdeaProjects/california-maven/target/classes/org/openjfx/fxml/sign-up.fxml:18
at javafx.fxml/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2603)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3237)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3194)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3163)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3136)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3113)
at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:3106)
at org.openjfx/org.openjfx.services.NavigationService.buildScene(NavigationService.java:43)
at org.openjfx/org.openjfx.services.NavigationService.push(NavigationService.java:55)
at org.openjfx/org.openjfx.controllers.LoginController.signUpLinkClicked(LoginController.java:74)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:76)
at jdk.internal.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at javafx.base/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:273)
at javafx.fxml/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:83)
at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1784)
at javafx.fxml/javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1670)
at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics/javafx.scene.Node.fireEvent(Node.java:8890)
at javafx.controls/javafx.scene.control.Hyperlink.fire(Hyperlink.java:156)
at javafx.controls/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:206)
at javafx.controls/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3862)
at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1849)
at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2590)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:409)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:299)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:447)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:412)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:446)
at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556)
at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942)
at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.IllegalStateException: Location is not set.
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2459)
at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
at org.openjfx/org.openjfx.components.GoBackButton.<init>(GoBackButton.java:18)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at java.base/java.lang.Class.newInstance(Class.java:584)
at javafx.fxml/javafx.fxml.FXMLLoader$InstanceDeclarationElement.constructValue(FXMLLoader.java:1019)
at javafx.fxml/javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:754)
at javafx.fxml/javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2722)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2552)
... 67 more
EDIT 2:
GoBackButton.java
package org.openjfx.components;
import javafx.fxml.FXML;
import org.openjfx.services.NavigationService;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import java.io.IOException;
import java.net.URL;
public class GoBackButton extends Button {
public GoBackButton() {
URL url = getClass().getResource("/org/openjfx/fxml/go-back-button.fxml");
FXMLLoader loader = new FXMLLoader(url);
try {
loader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public void onAction() {
NavigationService.getInstance().pop();
}
}
go-back-button.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<fx:root mnemonicParsing="false" fx:controller="org.openjfx.components.GoBackButton" onAction="#onAction" prefHeight="65.0" prefWidth="98.0" style="-fx-background-color: transparent;" styleClass="go-back-button" type="Button" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
<graphic>
<ImageView fitHeight="64.0" fitWidth="48.0" pickOnBounds="true" preserveRatio="true">
<Image url="@../img/arrow-left.png" />
</ImageView>
</graphic>
</fx:root>
The error still happens when I try to render the sign up page, but now the StackTrace changed. Link to pastebin since SO won't let me make a post this long.
Upvotes: 0
Views: 337
Reputation: 209299
The original error originates from creating the custom component GoBackButton
, as can be seen from the stack trace, which refers to line 18 of sign-up.fxml
(which is just <GoBackButton/>
) and subsequently line 18 of GoBackButton.java
, which is the loader.load()
line.
With the corrected URL for go-back-button.fxml
, you get a stack overflow exception as the custom component pattern is incorrectly implemented.
In your code, <GoBackButton/>
in sign-up.fxml
initiates a call to the GoBackButton
constructor. This constructor loads go-back-button.fxml
, which has the fx:controller
attribute set to GoBackButton
, which causes a call to the GoBackButton
constructor. This continues recursively, with repeated calls to loader.load()
and the constructor.
Instead, you need to set the controller to the current instance of GoBackButton
which is being constructed. You do this by omitting the fx:controller
attribute in go-back-button.fxml
and calling loader.setController(this)
before calling loader.load()
.
Additionally, since the custom component uses a dynamic root (with <fx:root>
), you need to explicitly set the root of the FXMLLoader
.
The resulting code should be
go-back-button.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<fx:root mnemonicParsing="false" onAction="#onAction" prefHeight="65.0" prefWidth="98.0" style="-fx-background-color: transparent;" styleClass="go-back-button" type="Button" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
<graphic>
<ImageView fitHeight="64.0" fitWidth="48.0" pickOnBounds="true" preserveRatio="true">
<Image url="@../img/arrow-left.png" />
</ImageView>
</graphic>
</fx:root>
and
GoBackButton.java
package org.openjfx.components;
import javafx.fxml.FXML;
import org.openjfx.services.NavigationService;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import java.io.IOException;
import java.net.URL;
public class GoBackButton extends Button {
public GoBackButton() {
URL url = getClass().getResource("/org/openjfx/fxml/go-back-button.fxml");
FXMLLoader loader = new FXMLLoader(url);
try {
loader.setController(this);
loader.setRoot(this);
loader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public void onAction() {
NavigationService.getInstance().pop();
}
}
Note: I've never actually tried setting an onAction
handler directly on a fx:root
element, but I believe it should work. You can also just do
public GoBackButton() {
URL url = getClass().getResource("/org/openjfx/fxml/go-back-button.fxml");
FXMLLoader loader = new FXMLLoader(url);
try {
loader.setController(this);
loader.setRoot(this);
loader.load();
setOnAction(e -> onAction());
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
Upvotes: 2