change label text of FXML scene from another class via controller class - javafx

I am relatively new to JavaFX, FXML and SceneBuilder in general. I am working on a project for uni where I have to build an application which includes the functionality of displaying different lecture profiles. The different profiles are stored in a database and are all instances of a class called "Lecture". I built a first simple scene for the class with SceneBuilder and also created a controller class. The idea now is that whenever a lecture should be displayed the according object is loaded from the database and used to adjust attributes in the controller class which cause the Scene to change. I simulated this by instantiating a Lecture object in my start() method and passing it to a getter-like method which was supposed to change the text of a first label attribute displaying the name of the lecturer. Unfortunately this causes a NullPointerException. All research couldn't help which is why I am here now. I am grateful for any help!
Picture of the GUI:
GUI
Error message with stacktrace:
> Task :Main.main() FAILED
Juni 23, 2022 12:16:04 AM com.sun.javafx.application.PlatformImpl startup
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module #1796cf6c'
Unsupported JavaFX configuration: classes were loaded from 'unnamed module #1796cf6c'
Juni 23, 2022 12:16:04 AM javafx.fxml.FXMLLoader$ValueElement processValue
WARNING: Loading FXML document with JavaFX API of version 18 by JavaFX runtime of version 17.0.1
Exception in Application start method
Loading FXML document with JavaFX API of version 18 by JavaFX runtime of version 17.0.1
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.NullPointerException: Cannot invoke "unihub.userapplicationsystem.LectureProfileController.loadLecture(unihub.serversystem.model.Lecture)" because "lectureProfileController" is null
at unihub.userapplicationsystem.GUI.start(GUI.java:25)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
Caused by: java.lang.NullPointerException: Cannot invoke "unihub.userapplicationsystem.LectureProfileController.loadLecture(unihub.serversystem.model.Lecture)" because "lectureProfileController" is null
at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Execution failed for task ':Main.main()'.
> Process 'command '/Library/Java/JavaVirtualMachines/jdk-17.0.1.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
JavaFX application class:
package unihub.userapplicationsystem;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import unihub.serversystem.model.Lecture;
import java.net.URL;
public class GUI extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
URL lectureProfileStageUML = ClassLoader.getSystemResource("LectureProfileStage.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
Parent root = fxmlLoader.load(lectureProfileStageUML);
Lecture testLecture = new Lecture(1, "EIST", "Krusche");
LectureProfileController lectureProfileController = fxmlLoader.getController();
lectureProfileController.loadLecture(testLecture);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
Main class:
public class Main {
public static void main(String[] args) {
GUI.main(args);
}
}
FXML controller class:
package unihub.userapplicationsystem;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import unihub.serversystem.model.Lecture;
public class LectureProfileController {
private Lecture lecture;
#FXML
private Label lecturerNameLabel;
public void loadLecture(Lecture lecture) {
lecturerNameLabel.setText("lecturer:\n" + lecture.getLecturer());
}
}
FXML file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Font?>
<ScrollPane prefHeight="500.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="unihub.userapplicationsystem.LectureProfileController">
<content>
<FlowPane prefHeight="500.0" prefWidth="400.0">
<children>
<StackPane prefHeight="100.0" prefWidth="400.0">
<children>
<ImageView fitHeight="100.0" fitWidth="400.0" pickOnBounds="true" preserveRatio="false">
<image>
<Image url="#LectureBanner.jpg" />
</image>
</ImageView>
<Label text="lecture name here" translateX="-85.0" translateY="-20.0" StackPane.alignment="BOTTOM_CENTER">
<font>
<Font name="SansSerif Bold" size="21.0" />
</font>
</Label>
</children>
</StackPane>
<GridPane alignment="BOTTOM_RIGHT" hgap="10.0" nodeOrientation="LEFT_TO_RIGHT" prefHeight="150.0" prefWidth="400.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="188.0" minWidth="10.0" prefWidth="167.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="173.0" minWidth="10.0" prefWidth="173.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="lecturer:
-lecturer here- " GridPane.halignment="LEFT" fx:id="lecturerNameLabel"/>
<Label text="lecture-ID:
-lecture-ID here-" GridPane.halignment="LEFT" GridPane.rowIndex="1" />
<Label text="teaching language:
-language here-" GridPane.halignment="LEFT" GridPane.rowIndex="2" />
<Label text="weekly hours:
-hours here-" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowIndex="1" />
<Label text="number of credits:
-credits here-" GridPane.columnIndex="1" GridPane.halignment="LEFT" />
<Button alignment="CENTER" mnemonicParsing="false" prefHeight="10.0" prefWidth="101.0" text="Enroll" GridPane.columnIndex="1" GridPane.rowIndex="2">
<font>
<Font name="SansSerif Regular" size="11.0" />
</font>
</Button>
</children>
<padding>
<Insets left="25.0" right="25.0" top="20.0" />
</padding>
</GridPane>
</children>
</FlowPane>
</content>
</ScrollPane>

The FXMLLoader.load(URL) method is a static method. So your code compiles to
URL lectureProfileStageUML = ClassLoader.getSystemResource("LectureProfileStage.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
Parent root = FXMLLoader.load(lectureProfileStageUML);
It's obvious from this equivalent version of the code that the instance you defined, fxmlLoader, has not been used to load an FXML file. Consequently it never initializes its controller, and
LectureProfileController lectureProfileController = fxmlLoader.getController();
returns null, resulting in a null pointer exception when you try to do
lectureProfileController.loadLecture(testLecture);
Instead, you should set the location of fxmlLoader and call the no-argument, instance method fxmlLoader.load():
#Override
public void start(Stage primaryStage) throws Exception {
URL lectureProfileStageUML = ClassLoader.getSystemResource("LectureProfileStage.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(lectureProfileStageUML);
// or just:
// FXMLLoader fxmlLoader = new FXMLLoader(lectureProfileStageUML);
// Note no URL is passed here:
Parent root = fxmlLoader.load();
Lecture testLecture = new Lecture(1, "EIST", "Krusche");
LectureProfileController lectureProfileController = fxmlLoader.getController();
lectureProfileController.loadLecture(testLecture);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
As an aside, the construction of your URL is probably wrong. See How do I determine the correct path for FXML files, CSS files, Images, and other resources needed by my JavaFX Application?
And as a second aside, it never makes sense to call a static method from an instance variable. Most IDEs warn you (or at the very least can be configured to warn you) when you accidentally do this. I recommend configuring your IDE to provide a warning (and not ignoring the warning). It was a poor design decision to allow that as valid syntax (the language designers were copying what happens in C++).

Related

While making own JOptionPane like class in JavaFX [duplicate]

I get
javafx.fxml.LoadException:
When I'm loading and fxml file using following line of code.
AnchorPane anchorPane = (AnchorPane)loader.load()
This is my fxml file excluding import statements.
<AnchorPane prefHeight="537.0" prefWidth="374.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.buddhikajay.controller.NewTransactionDialogController">
<children>
<GridPane hgap="5.0" layoutX="30.0" layoutY="10.0" prefHeight="544.0" prefWidth="314.0" vgap="5.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="142.0" minWidth="10.0" prefWidth="69.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="226.0" minWidth="10.0" prefWidth="225.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="70.0" minHeight="10.0" prefHeight="33.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="105.0" minHeight="10.0" prefHeight="38.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="156.0" minHeight="10.0" prefHeight="51.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="154.0" minHeight="10.0" prefHeight="43.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="160.0" minHeight="10.0" prefHeight="43.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="161.0" minHeight="10.0" prefHeight="63.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="301.0" minHeight="10.0" prefHeight="180.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="231.0" minHeight="10.0" prefHeight="106.0" vgrow="SOMETIMES" />
</rowConstraints>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<children>
<Label text="ID" />
<Label text="Date" GridPane.rowIndex="1" />
<Label text="Amont" GridPane.rowIndex="2" />
<Label text="Person" GridPane.rowIndex="4" />
<Label text="Type" GridPane.rowIndex="3" />
<Label text="Resolved" GridPane.rowIndex="5" />
<Label />
<Label text="Description" GridPane.rowIndex="6" />
<TextField fx:id="idTextField" GridPane.columnIndex="1" />
<TextField fx:id="dateTextField" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<TextField fx:id="amountTextField" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<TextArea fx:id="descriptionTextArea" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="6" />
<HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="50.0" prefWidth="225.0" spacing="20.0" GridPane.columnIndex="1" GridPane.rowIndex="7">
<GridPane.margin>
<Insets />
</GridPane.margin>
<padding>
<Insets bottom="10.0" left="20.0" right="10.0" top="10.0" />
</padding>
<children>
<Button fx:id="okButton" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#okActionFired" prefHeight="25.0" prefWidth="75.0" text="Ok" />
<Button fx:id="cancleButton" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#cancleActionFired" prefHeight="25.0" prefWidth="75.0" text="Cancle" />
</children>
</HBox>
<ComboBox fx:id="typeComboBox" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<ComboBox fx:id="personComboBox" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<ComboBox fx:id="resolvedComboBox" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="5" />
</children>
</GridPane>
</children>
</AnchorPane>
The compiler complains that there is an error in line number 1. I'm sure that the path of fxml file is correct. What is wrong with my code?
Here is the full error stack
javafx.fxml.LoadException:
/C:/Users/Buddhika/Documents/Programming/IdeaProjects/VirtualCreditDesktop/out/production/VirtualCreditDesktop/com/buddhikajay/view/NewTransactionDialog.fxml:9
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2595)
at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:104)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:928)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:967)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:216)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:740)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2701)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2521)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2435)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2403)
at com.buddhikajay.controller.NewTransactionDialogController.showNewTransactionDialog(NewTransactionDialogController.java:68)
at com.buddhikajay.controller.MainApp.start(MainApp.java:51)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(LauncherImpl.java:821)
at com.sun.javafx.application.LauncherImpl$$Lambda$50/1976027283.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(PlatformImpl.java:323)
at com.sun.javafx.application.PlatformImpl$$Lambda$46/301541210.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
at com.sun.javafx.application.PlatformImpl$$Lambda$48/474926796.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
at com.sun.javafx.application.PlatformImpl$$Lambda$47/1662429848.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
at com.sun.glass.ui.win.WinApplication$$Lambda$38/519284171.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.InstantiationException: com.buddhikajay.controller.NewTransactionDialogController
at java.lang.Class.newInstance(Class.java:423)
at sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:51)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:923)
... 23 more
Caused by: java.lang.NoSuchMethodException: com.buddhikajay.controller.NewTransactionDialogController.<init>()
at java.lang.Class.getConstructor0(Class.java:3074)
at java.lang.Class.newInstance(Class.java:408)
... 25 more
The problem is described in the stack trace:
Caused by: java.lang.NoSuchMethodException: com.buddhikajay.controller.NewTransactionDialogController.()
which basically says your controller class doesn't have a zero-argument constructor.
By default, the FXMLLoader will create the controller by calling its zero-argument constructor. Remove the constructor that you have defined in the controller class, or remove the parameters that it takes.
If you really need to pass arguments to the controller's constructor, you can either create the controller in Java code and pass it to the FXMLLoader:
NewTransactionDialogController controller = new NewTransactionDialogController(someValue);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(...);
loader.setController(controller);
AnchorPane anchorPane = loader.load();
(Using this code, you must remove the fx:controller attribute from the FXML.)
Or, set a controller factory:
FXMLLoader loader = new FXMLLoader();
loader.setLocation(...);
loader.setControllerFactory(clazz -> {
if (clazz == NewTransactionDialogController.class) {
return new NewTransactionDialogController(someValue);
} else {
// default behavior:
try {
return clazz.newInstance();
} catch (Exception exc) {
throw new RuntimeException(exc);
}
}
});
AnchorPane anchorPane = loader.load();
(In this version, leave the fx:controller attribute in the FXML file.)
I was about to enter a different question as remarked by #James_D for my comment because Until I Read the first line of the FXML on this question, I had thought that I had a different problem.
For my sins, I reduced the challenge to a simple example of a single controller and two FXML files. One worked and the second fail/failed.
The starting point is the Netbeans sample "[Click me!]" sample. The code is pasted below. And, first a solution.
As preamble, let me say that it seems that everyone has been blaming the Java controller for these load errors. I had a bunch of errors like this on a project a couple of years ago. We exhausted "controller" debugging and eventually pressed-forward by re-building the FXML screens with ScendBuilder. I didn't have time to investigate further then.
Last week I perfectly working FXML screen started failing to load because we moved it to a runtime directory (previously it was in the JAR resources area).
KLUNK!
After 3 or 4 days tweaking that and this, I made a comment here on my error:
unknown path: 7
Javafx fxml LoadException: Error resolving onAction='#handleButtonAction', either the event handler is not in the Namespace or there is an error in the script.
On only the "simple.fxml" file, but not the "Scene.fxml" file. The file "simple.fxml" is reduced from the app FXML file that initially gave the problem. There were too many variables on that original file, so chop-chop-chop to match the canned demo.
When you use ONLY this:
xmlns:fx="http://javafx.com/fxml"
FXML load-s from files on disk under in your application folder work just like you want them to (well, like I want, anyway). Looking at the FXML above it is using a more 'fragile' namespace, viz.
Queston's original FXML:
<AnchorPane ...
xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1" ... >
By using diff, I slowly morphed "simple.fxml" to be as close as possible to "Scene.fxml", and "simple" just keeps failing to load. Please note; always using the same controller
Loading FXML with other metadata has not worked consistently an FXML file was moved. I don't have an explanation as to how this is so.
The FXML is kept in a directory called "test/resources/fxml/simple.fxml" for example. When I was building with both files in the project JAR, the 'same' FXML in both cases loaded and worked as expected. To me there's something un-said about aspects of the file load precess. Again for me, this is undesirable because the KEY value of a external scene definition would be interchange.
These kind of bear traps in XML mark-up that are (apparently) not picked up by development tools like SceneBuilder or the FXMLLoader() are barriers to progress on live projects that don't have slack to investigate esoteric weirdness like this.
This is witnessed by our previous project experience -- I was easier to re-edit a complex screen with SceneBuilder as a whole than track down load problems like this one. The call to action is: Diagnostics on FXML load -- an FXML Lint would be almost a requirement.
Controller, SimpleController.java:
package ex.view.views;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
public class SimpleController implements Initializable {
#FXML
private Label label;
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
The failing FXML started life as one of the Maven archetypes (I think) and that file worked fine until I moved the FXML files to a folder and loaded them from a InputStream.
I have formatted the AnchorPane markup on multiple lines for readability.
simple.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320"
xmlns="http://javafx.com/javafx/8.0.65"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="ex.view.views.SimpleController">
<children>
<Button fx:id="button" layoutX="126" layoutY="90" text="Click Me!" />
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
</children>
</AnchorPane>
The working FXML mark-up is from the Netbeans 8.1 samples.
Scene.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320"
xmlns:fx="http://javafx.com/fxml"
fx:controller="ex.view.views.SimpleController">
<children>
<Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
<Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
</children>
</AnchorPane>

Placing a JavaFX custom control in a GridPane

I followed Oracle's Mastering FXML tutorial, specifically the tutorial for making a custom control, works fine as a standalone. But if I want to place this custom control in a GridPane, how can I place it with the GridPane's column and row attributes? Trying to place the custom control in the FXML file just gives me an error that the class is not a valid type.
My custom control FXML (view_navigation.fxml):
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<fx:root type="javafx.scene.layout.HBox" xmlns:fx="http://javafx.com/fxml">
<Button>
<graphic>
<ImageView>
<Image url="#/toolbarButtonGraphics/navigation/Back24.gif"/>
</ImageView>
</graphic>
</Button>
<Button text="Add Entry" />
<Button text="Change Entry" />
<Button text="View List" />
<Button>
<graphic>
<ImageView>
<Image url="#/toolbarButtonGraphics/navigation/Forward24.gif"/>
</ImageView>
</graphic>
</Button>
</fx:root>
Its associated class (ViewNavigationControl.java):
import java.io.IOException;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.HBox;
public class ViewNavigationControl extends HBox {
public ViewNavigationControl() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("view_navigation.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
}
Placing it at the bottom of the parent view's GridPane, per the very last paragraph in the tutorial:
....
<HBox GridPane.columnIndex="0" GridPane.rowIndex="3" GridPane.columnSpan="2">
<ViewNavigationControl />
</HBox>
</GridPane>
I get javafx.fxml.LoadException: ViewNavigationControl is not a valid type.
THANKS for any help at all!

onAction="#ClickedClickMe" not working in JavaFX FXML

Good Morning! I have just started ramping up on Java FX and Java FX FXML. I'm using Scene Builder to build the GUI and Netbeans to code the remaining Java FX program.
The issue I'm facing is in FXML File. The Netbeans editor shows an error on the following code in .fxml file for onAction Event.
Error that I see in fxml file:
Controller is NOT defined on root component.
Exception Text:
Executing sample1.jar using platform C:\Program
Files\Java\jdk1.8.0_121\jre/bin/java Exception in Application start
method java.lang.reflect.InvocationTargetException at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498) at
com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at
com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498) at
sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start
method at
com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at
com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:745) Caused by:
javafx.fxml.LoadException: No controller specified.
file:/C:/Users/hmitty/Documents/NetBeansProjects/sample1/dist/run1317822864/sample1.jar!/sample1/FXMLDocument.fxml:21
at
javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2597)
at javafx.fxml.FXMLLoader.access$100(FXMLLoader.java:103) at
javafx.fxml.FXMLLoader$Element.getControllerMethodHandle(FXMLLoader.java:557)
at
javafx.fxml.FXMLLoader$Element.processEventHandlerAttributes(FXMLLoader.java:599)
at
javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:770)
at javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2823) at
javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2532) 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
sample1.Sample1.start(Sample1.java:22) 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.win.WinApplication._runLoop(Native Method) at
com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
... 1 more Exception running application sample1.Sample1 Picked up
_JAVA_OPTIONS: -Djava.net.preferIPv4Stack=true Java Result: 1
If I create a sample project using Netbeans, it uses AnchorPane and everything seems to be fine. However if I remove AnchorPane and add any other pane and the Button, the onAction Event doesn't work!
I'm a beginner in this language, hence any help/guidance is highly appreciated!
Note: I did my homework for close to half a day in browsing all available solutions as far as I can on StackOverFlow.
The closest I got is this, so any help will definitely move things for me!
https://bugs.openjdk.java.net/browse/JDK-8091582
All the code is pasted below. Let me know if anything else is required!
FXML Code:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.event.ActionEvent?>
<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Button mnemonicParsing="false" onAction="#ClickedClickMe" text="Click Me!" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label fx:id="label" GridPane.columnIndex="1" GridPane.rowIndex="2" />
</children>
</GridPane>
Sample1.java
package sample1;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Sample1 extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
FXMLDocumentController.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package sample1;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
public class FXMLDocumentController implements Initializable {
#FXML
private Label label;
#FXML
private void ClickedClickMe(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Clicked Try me!!");
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Set controller in fxml file
<GridPane fx:controller="sample1.FXMLDocumentController" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111">

JavaFX Custom Control revisited

I have run the Mastering FXML example, How to create custom components in JavaFX 2.0 using FXML and tried various other solutions from this site, but I still haven't found a simple enough example showing how to set up a custom control that is NOT the only part of the GUI. Since the question is still popping up it seems we need a simpler example for some of us..
I'm trying to create a simple control consisting of a vertical SplitPane with a Button in the top section and a label in the lower section. Then I want to place instances of this SplitPane-control in multiple tabs in a TabPane.
Either the control won't show up, or I get stuck in various errors, depending on which example I try to follow. So, I'll backtrack a bit and will just simply ask: How do I separate out the SplitPane to be the custom control here?
Here is the FXML document:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>
<TabPane prefHeight="256.0" prefWidth="477.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="customcontroltest.FXMLDocumentController">
<tabs>
<Tab>
<content>
<SplitPane dividerPositions="0.5" orientation="VERTICAL" prefHeight="114.0" prefWidth="160.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<Button fx:id="button" onAction="#handleButtonAction" text="Click Me!" />
</children>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<Label fx:id="label" minHeight="16" minWidth="69" />
</children>
</AnchorPane>
</items>
</SplitPane>
</content>
</Tab>
</tabs>
</TabPane>
And the controller class:
package customcontroltest;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
public class FXMLDocumentController implements Initializable
{
#FXML
private Label label;
#FXML
private void handleButtonAction(ActionEvent event)
{
label.setText("Hello World!");
}
#Override
public void initialize(URL url, ResourceBundle rb)
{
// TODO
}
}
And the main test class:
package customcontroltest;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class CustomControlTest extends Application
{
#Override
public void start(Stage stage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
I made a new FXML file and cut/pasted the whole SplitPane tag and all its contents into it. I replaced the SplitPane tag in the FXML document with <packageName.ControlClassName />. Then I made the controller class to extend SplitPane. I've tried specifying the controller in the FXML tag and/or in the controller class, but never got it right.
Would someone with the right knowledge be willing to take a few minutes to just show a working example of this? I'm guessing more people would find such an example very useful.
So, the SplitPane should be the new custom control, and you can then by default load it into the first tab in the TabPane. Then I will write code to add more instances into subsequent tabs.
Thank you so very much in advance.
UPDATE:
I have broken out the SplitPane into its own FXML and controller class.
Here is the FXML (CustomSplitPane.fxml):
<fx:root type="javafx.scene.control.SplitPane" dividerPositions="0.5" orientation="VERTICAL" prefHeight="114.0" prefWidth="160.0" xmlns:fx="http://javafx.com/fxml/1" fx:controller="customcontroltest.CustomSplitPaneController">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<Button fx:id="button" onAction="#handleButtonAction" text="Click Me!" />
</children>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<Label fx:id="label" minHeight="16" minWidth="69" />
</children>
</AnchorPane>
</items>
</fx:root>
And the controller class (CustomSplitPaneController.java):
package customcontroltest;
public class CustomSplitPaneController extends AnchorPane
{
#FXML
private Label label;
private SplitPane mySplitPane;
public CustomSplitPaneController()
{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("CustomSplitPane.fxml"));
try
{
fxmlLoader.load();
} catch (IOException exception)
{
throw new RuntimeException(exception);
}
}
#FXML
private void handleButtonAction(ActionEvent event)
{
label.setText("Hello World!");
}
}
And the original main FXML now looks like this:
<TabPane prefHeight="256.0" prefWidth="477.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="customcontroltest.FXMLDocumentController">
<tabs>
<Tab>
<content>
<customcontroltest.CustomSplitPaneController />
</content>
</Tab>
</tabs>
</TabPane>
The fxmlLoader.load() in the CustomSplitPaneController seems to be causing a java.lang.StackOverflowError.
Maybe it's more evident now to someone here what I'm missing?
Thanks again.
The fx:controller attribute in an FXML file is an instruction for the FXML loader to create an instance of the specified class and use it as the controller for the UI hierarchy defined by the FXML.
In the attempt to create a custom split pane that you posted, what happens when you create an instance of CustomSplitPaneController is:
You create an FXMLLoader in the constructor of CustomSplitPaneController, which loads CustomSplitPane.fxml
CustomSplitPane.fxml has a fx:controller attribute specifying CustomSplitPaneController as the controller class, so it creates a new instance of CustomSplitPaneController (by calling its constructor, of course)
The constructor of CustomSplitPaneController creates an FXMLLoader which loads CustomSplitPane.fxml
and so on.
So very quickly, you get a stack overflow exception.
Control classes in JavaFX encapsulate both the view and the controller. In the standard JavaFX control classes the view is represented by a Skin class, and the controller by a Behavior class. The control class itself extends Node (or a subclass: Region) and when you instantiate it, it instantiates both the skin and the behavior. The skin defines the layout and appearance of the control, and the behavior maps various input actions to actual code that modifies the properties of the control itself.
In the pattern you are trying to replicate, shown here and here, this is slightly modified. In this version, the "view" is defined by an FXML file, and the controller (the behavior) is implemented directly in the control class itself (there is no separate behavior class).
To make this work, you have to use FXML slightly differently to usual. First, when you use your custom control, you are going to instantiate the control class directly (without any knowledge of the FXML that defines its layout). So if you are using this in java, you would do new CustomSplitPane(), and if you are using it in FXML you would do <CustomSplitPane>. Either way, you invoke the constructor of your custom control (which I'm calling CustomSplitPane).
To use CustomSplitPane in the UI hierarchy, it must of course be a Node subclass. If you want it to be a kind of SplitPane, you would make it extend SplitPane:
public class CustomSplitPane extends SplitPane {
// ...
}
Now, in the constructor of CustomSplitPane, you need to load the FXML file that defines the layout, but you need it to lay out the current object. (In the usual usage of an FXML file, the FXMLLoader creates a new node for the root of the hierarchy, of the type specified, and the load() method returns it. You want the FXMLLoader to use the existing object as the root of the hierarchy.) To do this, you use the <fx:root> element as the root element of the FXML file, and you tell the FXMLLoader to use this as the root:
loader.setRoot(this);
Additionally, since the handler methods are defined in the current object, you also want the controller to be the current object:
loader.setController(this);
Since you are specifying an existing object as the controller, you must not have a fx:controller attribute in the FXML file.
So you end up with:
package customcontroltest;
public class CustomSplitPane extends SplitPane {
#FXML
private Label label;
public CustomSplitPaneController() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("CustomSplitPane.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
#FXML
private void handleButtonAction(ActionEvent event)
label.setText("Hello World!");
}
}
and the FXML file:
<fx:root type="javafx.scene.control.SplitPane" dividerPositions="0.5" orientation="VERTICAL" prefHeight="114.0" prefWidth="160.0" xmlns:fx="http://javafx.com/fxml/1" >
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<Button fx:id="button" onAction="#handleButtonAction" text="Click Me!" />
</children>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<Label fx:id="label" minHeight="16" minWidth="69" />
</children>
</AnchorPane>
</items>
</fx:root>
And now you can use this in another FXML file as you need:
<TabPane prefHeight="256.0" prefWidth="477.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="customcontroltest.FXMLDocumentController">
<tabs>
<Tab>
<content>
<customcontroltest.CustomSplitPane />
</content>
</Tab>
</tabs>
</TabPane>
Your custom control class should extends one of the Parent class, for example Region or Pane. If you are too lazy to do layout stuff, just extend an advanced pane like GridPane.
Then your custom control class should load an FXML containing the SplitPane and its children. The controller for the FXML can be simply this custom control class, or you can still separate it out to its personal controller class. The SplitPane node should be added as a child of the custom control class; this means that your custom control (which is a Parent type), has to handle some layout logic. At this point, your custom control is complete.
This control is ready to be used in FXML. However, if you want to use it in Scene Builder, you need to package it into a JAR file, and add it to Scene Builder. Note that in order for Scene Builder to work, your custom control class MUST have a parameterless constructor defined.
I'm not entirely sure if this is what you're looking for, but JavaFX controls are based on the Model, View, Controller (MVC) pattern.
Model
Where the Model class is where the any information is stored for your system. For example, if you had a textField, you'd store what value the text field is holding in the model class. I always think of it as a miniature database for my control.
View
The View class is visually what your control looks like. Defining the size, shape, color, etc. A note on "color", this is where you'd set the default color of your control. (this could also be done using FXML, but I personally would rather use java code). The model is often passed to the View constructor as an argument for binding using bean properties. (For java, not sure how you'd do it for FXML)
Controller
The controller class is where manipulation can occur. If I click a button, or change something in my textField, what does the controller do or how does it manipulate the model. The Model and View are both passed as argument to the controller. This gives the controller a reference to the model and the view which allows the controller to manipulate each as designed. Other outside classes can interact with your controller class and your controller class acts on the model and view.
With that said, without any additional information, it looks like everything you're doing is just combining existing controls into something pre-defined for reuse. It may be worth looking into defining a class that extends SplitPane, and a constructor that already adds your button and label to where you want them. Your new class could then be treated like a SplitPane as well as have your action for your button built in.
A really good break down of this is in the book,
Apress JavaFX 8 Introduction By Example Chapter 6
OK, so here is the working solution all laid out, file by file. Hopefully this is useful to someone else too.
CustomControlTest.java
package customcontroltest;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class CustomControlTest extends Application
{
#Override
public void start(Stage stage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
FXMLDocument.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>
<TabPane prefHeight="256.0" prefWidth="477.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="customcontroltest.FXMLDocumentController">
<tabs>
<Tab>
<content>
<customcontroltest.CustomSplitPaneController />
</content>
</Tab>
</tabs>
</TabPane>
FXMLDocumentController.java
package customcontroltest;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
public class FXMLDocumentController implements Initializable
{
#Override
public void initialize(URL url, ResourceBundle rb)
{
// TODO
}
}
CustomSplitPane.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<fx:root type="javafx.scene.control.SplitPane" dividerPositions="0.5" orientation="VERTICAL" prefHeight="114.0" prefWidth="160.0" xmlns:fx="http://javafx.com/fxml/1" >
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<Button fx:id="button" onAction="#handleButtonAction" text="Click Me!" />
</children>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<Label fx:id="label" minHeight="16" minWidth="69" />
</children>
</AnchorPane>
</items>
</fx:root>
The NetBeans IDE will give an error on #handleButtonAction, saying "Controller is not defined on root component", but it won't actually give compilation errors. (This is where I was tricked into not even trying to compile when I saw that highlighted error!)
CustomSplitPaneController.java
package customcontroltest;
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.control.SplitPane;
public class CustomSplitPaneController extends SplitPane
{
#FXML
private Label label;
public CustomSplitPaneController()
{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("CustomSplitPane.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try
{
fxmlLoader.load();
} catch (IOException exception)
{
throw new RuntimeException(exception);
}
}
#FXML
private void handleButtonAction(ActionEvent event)
{
label.setText("Hello World!");
}
}

Why I'm getting javafx.fxml.LoadException even the path of the fxml file is correct

I get
javafx.fxml.LoadException:
When I'm loading and fxml file using following line of code.
AnchorPane anchorPane = (AnchorPane)loader.load()
This is my fxml file excluding import statements.
<AnchorPane prefHeight="537.0" prefWidth="374.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.buddhikajay.controller.NewTransactionDialogController">
<children>
<GridPane hgap="5.0" layoutX="30.0" layoutY="10.0" prefHeight="544.0" prefWidth="314.0" vgap="5.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="142.0" minWidth="10.0" prefWidth="69.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="226.0" minWidth="10.0" prefWidth="225.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="70.0" minHeight="10.0" prefHeight="33.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="105.0" minHeight="10.0" prefHeight="38.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="156.0" minHeight="10.0" prefHeight="51.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="154.0" minHeight="10.0" prefHeight="43.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="160.0" minHeight="10.0" prefHeight="43.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="161.0" minHeight="10.0" prefHeight="63.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="301.0" minHeight="10.0" prefHeight="180.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="231.0" minHeight="10.0" prefHeight="106.0" vgrow="SOMETIMES" />
</rowConstraints>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<children>
<Label text="ID" />
<Label text="Date" GridPane.rowIndex="1" />
<Label text="Amont" GridPane.rowIndex="2" />
<Label text="Person" GridPane.rowIndex="4" />
<Label text="Type" GridPane.rowIndex="3" />
<Label text="Resolved" GridPane.rowIndex="5" />
<Label />
<Label text="Description" GridPane.rowIndex="6" />
<TextField fx:id="idTextField" GridPane.columnIndex="1" />
<TextField fx:id="dateTextField" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<TextField fx:id="amountTextField" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<TextArea fx:id="descriptionTextArea" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="6" />
<HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="50.0" prefWidth="225.0" spacing="20.0" GridPane.columnIndex="1" GridPane.rowIndex="7">
<GridPane.margin>
<Insets />
</GridPane.margin>
<padding>
<Insets bottom="10.0" left="20.0" right="10.0" top="10.0" />
</padding>
<children>
<Button fx:id="okButton" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#okActionFired" prefHeight="25.0" prefWidth="75.0" text="Ok" />
<Button fx:id="cancleButton" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#cancleActionFired" prefHeight="25.0" prefWidth="75.0" text="Cancle" />
</children>
</HBox>
<ComboBox fx:id="typeComboBox" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<ComboBox fx:id="personComboBox" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<ComboBox fx:id="resolvedComboBox" prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="5" />
</children>
</GridPane>
</children>
</AnchorPane>
The compiler complains that there is an error in line number 1. I'm sure that the path of fxml file is correct. What is wrong with my code?
Here is the full error stack
javafx.fxml.LoadException:
/C:/Users/Buddhika/Documents/Programming/IdeaProjects/VirtualCreditDesktop/out/production/VirtualCreditDesktop/com/buddhikajay/view/NewTransactionDialog.fxml:9
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2595)
at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:104)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:928)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:967)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:216)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:740)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2701)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2521)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2435)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2403)
at com.buddhikajay.controller.NewTransactionDialogController.showNewTransactionDialog(NewTransactionDialogController.java:68)
at com.buddhikajay.controller.MainApp.start(MainApp.java:51)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(LauncherImpl.java:821)
at com.sun.javafx.application.LauncherImpl$$Lambda$50/1976027283.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(PlatformImpl.java:323)
at com.sun.javafx.application.PlatformImpl$$Lambda$46/301541210.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
at com.sun.javafx.application.PlatformImpl$$Lambda$48/474926796.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
at com.sun.javafx.application.PlatformImpl$$Lambda$47/1662429848.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
at com.sun.glass.ui.win.WinApplication$$Lambda$38/519284171.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.InstantiationException: com.buddhikajay.controller.NewTransactionDialogController
at java.lang.Class.newInstance(Class.java:423)
at sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:51)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:923)
... 23 more
Caused by: java.lang.NoSuchMethodException: com.buddhikajay.controller.NewTransactionDialogController.<init>()
at java.lang.Class.getConstructor0(Class.java:3074)
at java.lang.Class.newInstance(Class.java:408)
... 25 more
The problem is described in the stack trace:
Caused by: java.lang.NoSuchMethodException: com.buddhikajay.controller.NewTransactionDialogController.()
which basically says your controller class doesn't have a zero-argument constructor.
By default, the FXMLLoader will create the controller by calling its zero-argument constructor. Remove the constructor that you have defined in the controller class, or remove the parameters that it takes.
If you really need to pass arguments to the controller's constructor, you can either create the controller in Java code and pass it to the FXMLLoader:
NewTransactionDialogController controller = new NewTransactionDialogController(someValue);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(...);
loader.setController(controller);
AnchorPane anchorPane = loader.load();
(Using this code, you must remove the fx:controller attribute from the FXML.)
Or, set a controller factory:
FXMLLoader loader = new FXMLLoader();
loader.setLocation(...);
loader.setControllerFactory(clazz -> {
if (clazz == NewTransactionDialogController.class) {
return new NewTransactionDialogController(someValue);
} else {
// default behavior:
try {
return clazz.newInstance();
} catch (Exception exc) {
throw new RuntimeException(exc);
}
}
});
AnchorPane anchorPane = loader.load();
(In this version, leave the fx:controller attribute in the FXML file.)
I was about to enter a different question as remarked by #James_D for my comment because Until I Read the first line of the FXML on this question, I had thought that I had a different problem.
For my sins, I reduced the challenge to a simple example of a single controller and two FXML files. One worked and the second fail/failed.
The starting point is the Netbeans sample "[Click me!]" sample. The code is pasted below. And, first a solution.
As preamble, let me say that it seems that everyone has been blaming the Java controller for these load errors. I had a bunch of errors like this on a project a couple of years ago. We exhausted "controller" debugging and eventually pressed-forward by re-building the FXML screens with ScendBuilder. I didn't have time to investigate further then.
Last week I perfectly working FXML screen started failing to load because we moved it to a runtime directory (previously it was in the JAR resources area).
KLUNK!
After 3 or 4 days tweaking that and this, I made a comment here on my error:
unknown path: 7
Javafx fxml LoadException: Error resolving onAction='#handleButtonAction', either the event handler is not in the Namespace or there is an error in the script.
On only the "simple.fxml" file, but not the "Scene.fxml" file. The file "simple.fxml" is reduced from the app FXML file that initially gave the problem. There were too many variables on that original file, so chop-chop-chop to match the canned demo.
When you use ONLY this:
xmlns:fx="http://javafx.com/fxml"
FXML load-s from files on disk under in your application folder work just like you want them to (well, like I want, anyway). Looking at the FXML above it is using a more 'fragile' namespace, viz.
Queston's original FXML:
<AnchorPane ...
xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1" ... >
By using diff, I slowly morphed "simple.fxml" to be as close as possible to "Scene.fxml", and "simple" just keeps failing to load. Please note; always using the same controller
Loading FXML with other metadata has not worked consistently an FXML file was moved. I don't have an explanation as to how this is so.
The FXML is kept in a directory called "test/resources/fxml/simple.fxml" for example. When I was building with both files in the project JAR, the 'same' FXML in both cases loaded and worked as expected. To me there's something un-said about aspects of the file load precess. Again for me, this is undesirable because the KEY value of a external scene definition would be interchange.
These kind of bear traps in XML mark-up that are (apparently) not picked up by development tools like SceneBuilder or the FXMLLoader() are barriers to progress on live projects that don't have slack to investigate esoteric weirdness like this.
This is witnessed by our previous project experience -- I was easier to re-edit a complex screen with SceneBuilder as a whole than track down load problems like this one. The call to action is: Diagnostics on FXML load -- an FXML Lint would be almost a requirement.
Controller, SimpleController.java:
package ex.view.views;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
public class SimpleController implements Initializable {
#FXML
private Label label;
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
The failing FXML started life as one of the Maven archetypes (I think) and that file worked fine until I moved the FXML files to a folder and loaded them from a InputStream.
I have formatted the AnchorPane markup on multiple lines for readability.
simple.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320"
xmlns="http://javafx.com/javafx/8.0.65"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="ex.view.views.SimpleController">
<children>
<Button fx:id="button" layoutX="126" layoutY="90" text="Click Me!" />
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
</children>
</AnchorPane>
The working FXML mark-up is from the Netbeans 8.1 samples.
Scene.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320"
xmlns:fx="http://javafx.com/fxml"
fx:controller="ex.view.views.SimpleController">
<children>
<Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
<Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
</children>
</AnchorPane>

Resources