I'm hoping someone can either explain to me what I am doing wrong, or point me to the answer if this has been answered previously (I've been rooting around hereabouts for 2 days looking for an answer).
I am trying to create an demo application that launches a JavaFX GUI. When my app is ready to launch the GUI (the app has to take care of things in the background first), I call:
Application.launch(StarFXDemo.class, "");
Here is StarFXDemo.java:
package standalonedemo;
import java.io.IOException;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class StarFXDemo extends Application
{
@Override
public void start(Stage stage) throws Exception
{
Parent root = null;
try
{
root = FXMLLoader.load(getClass().getResource("StarFXDemoDoc.fxml"));
} catch (IOException ioe)
{
ioe.printStackTrace(System.out);
}
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}
StarFXDemoDoc.fxml is in the JAR file & is the same package as StarFXDemo (rather than in another package or in a sub package). So
getClass().getResource("/standalonedemo/resources/StarFXDemoDoc.fxml")
Comes back with a URL to the file.
StarFXDemoDoc.fxml is this:
<?xml version="1.0" encoding="UTF-8"?>
<?import standalonedemo.*?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<TitledPane animated="false" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" text="FX Sim Demo"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="standalonedemo.StarFXDemoDocController">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<VBox prefHeight="85.0" prefWidth="322.0" spacing="5.0" style="-fx-background-color: coral;">
<children>
<Label text="Sim Title" />
<TextField fx:id="SimNameField" onMouseDragExited="#setSimulationName" />
</children>
<padding>
<Insets left="25.0" top="15.0" />
</padding>
</VBox>
<Button fx:id="BuildSphereButton" layoutX="14.0" layoutY="100.0" mnemonicParsing="false" onAction="#buildSphereAction" text="Build Sphere" />
</children></AnchorPane>
</content>
</TitledPane>
And StarFXDemoDocController.java is this:
package standalonedemo;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
public class StarFXDemoDocController implements Initializable
{
@FXML
private TextField SimNameField;
@FXML
private Button BuildSphereButton;
/**
* RequiredConstructor
*/
public StarFXDemoDocController() {}
@Override
public void initialize(URL url, ResourceBundle rb)
{
}
@FXML
private void buildSphereAction(ActionEvent event)
{
}
@FXML
private void setSimulationName()
{
}
}
There is nothing really in the methods yet because I'm just trying to get the GUI to appear at this time. I have the empty constructor, and the @FXML tags on the GUI elements with fx:id tags (as well as their corresponding methods).
When I run the program, at the point I call
FXMLLoader.load(getClass().getResource("/standalonedemo/resources/StarFXDemoDoc.fxml"));
it throws the following exception (this exception is no longer relevant, see the exception below):
I am assuming I have something formatted wrong, but I have no idea what it is.
Can anyone help me out here?
EDIT/UPDATE:
As per James_D's comments (thank you James, obviously I had been staring at that for way too long...), I fixed the obvious error in my controller and made SimNameField a TextField, rather than a Label (and updated the code block above to reflect this). I also changed the exception handling to use printStackTrace. The changes now get me the following stack trace:
javafx.fxml.LoadException: file:<properPathTo>/StandAloneDemo/dist/StandAloneDemo.jar!/standalonedemo/resources/StarFXDemoDoc.fxml:11
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:103)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:922)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:971)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:220)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:744)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
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 standalonedemo.StarFXDemo.start(StarFXDemo.java:35)
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)
Caused by: java.lang.ClassNotFoundException: standalonedemo.StarFXDemoDocController starting from SystemClassLoader[55 modules] with possible defining loaders null and declared parents [org.netbeans.MainImpl$BootClassLoader@97e1986, ModuleCL@1fa50985[org.netbeans.api.annotations.common], ModuleCL@7251b0ac[org.openide.awt], ModuleCL@7d1344a8[org.netbeans.api.progress], ModuleCL@26b9eb92[org.netbeans.swing.plaf], ModuleCL@7feb85da[org.openide.dialogs], ModuleCL@15c98cea[org.openide.nodes], ModuleCL@ed11c24[org.openide.windows], ModuleCL@621f6603[org.netbeans.swing.tabcontrol], ModuleCL@2a3ed4eb[org.netbeans.swing.outline], ...40 more]
at org.netbeans.ProxyClassLoader.loadClass(ProxyClassLoader.java:224)
at org.netbeans.ModuleManager$SystemClassLoader.loadClass(ModuleManager.java:722)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:920)
... 22 more
Caused by: java.lang.ClassNotFoundException: standalonedemo.StarFXDemoDocController
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.netbeans.ProxyClassLoader.loadClass(ProxyClassLoader.java:222)
... 25 more
So I see the ClassNotFoundException, which got me to start looking at my controller class some more, and I noticed that Scene Builder has all but decided that my TextField doesn't exist as a tagged item (when I assign the fx:id of simNameField to the TextField in Scene Builder, I get the "No injectable field..." warning, and right clicking on the fx:id field for the control only shows the buildSphereButton tag). So I removed the simNameField from the controller class, right clicked on the FXML file in NetBeans, and told it to Make Controller. It added the TextField back with the correct fx:id and @FXML tag. Scene Builder still thinks it's an fx:id without an injectable field.
So I obviously have some manner of disconnect between the FXML and the controller, but I have no clue what it could be?
UPDATE2:
Took out the first stack trace, as it was no longer relevant and updated a few lines of code (like adding the import for the package to the FXML).
Been playing with it. If I remove the controller reference, the GUI launches as expected (so we know the FXML file is loading). If I instantiate a Controller object (before I call FXMLLoader.load(<...>)), it instantiates as expected, and I can verify that it is not null through the NetBeans debugger, so I know that the controller class is compiled, and on the class path.
So why can't the FXMLLoader find it? Should I be using an alternative method to load it? I've thought about just creating the controller object in the code and setting it that way, but that seems to annoy NetBeans when it comes to the fx:controller statement (i.e. If you have elements in the FXML that require a controller, and that statement isn't in there, NetBeans flags it as incorrect).
TextFieldto aLabel... - James_DiOException.printStackTrace()in the catch block. - James_D