I'm not sure where I should be putting my <fx:include fx:id="NTB" source="NTB.fxml" />
in my main .fxml file. I'll include the relevant files at the bottom.
File Structure:
Test.java displays a TableView as well as a toolbar that contains some buttons. When the newTask button is clicked I'm trying to have it call the display()
method from NTB.java which will display a new window that takes some input from the user and stores it in a list that's visible to that class. Once the user clicks the done button in that new window the window closes and updates the table contents.
Currently with how these files are setup the program will compile and run and when the newTask button is clicked it produces an error but doesn't crash which is expected since the NTBController is null by default since the <fx:include />
tag isn't present yet.
The main issue I'm having is that so far no matter where I've put the <fx:include />
tag in Test.fxml the program doesn't launch at produces an error that points to the line the include tag is on in Test.fxml, the last line of the BorderPane definition in NTB.fxml, and the loadFXML & start function in Test.java.
Relevant files:
Test.fxml:
<?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.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="1080.0" prefWidth="1920.0" fx:controller="com.test.Controller" xmlns="http://javafx.com/javafx/13" xmlns:fx="http://javafx.com/fxml/1">
<fx:include fx:id="nTB" source="NTB.fxml" />
<center>
<TableView fx:id="table" prefHeight="352.0" prefWidth="543.0">
<columns>
<TableColumn fx:id="orderCol" prefWidth="75.0" text="Order" />
<TableColumn fx:id="nameCol" prefWidth="75.0" text="Name" />
<TableColumn fx:id="xCol" prefWidth="75.0" text="X" />
<TableColumn fx:id="yCol" prefWidth="75.0" text="Y" />
<TableColumn fx:id="buttonCol" prefWidth="75.0" text="Button" />
<TableColumn fx:id="keyCol" prefWidth="75.0" text="Key Code" />
<TableColumn fx:id="descriptionCol" prefWidth="75.0" text="Description" />
<TableColumn fx:id="delayCol" prefWidth="75.0" text="Delay" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
</center>
<top>
<HBox alignment="CENTER" prefHeight="34.0" prefWidth="600.0">
<children>
<Button fx:id="newTask" mnemonicParsing="false" onAction="#newTaskDisplay" text="New" />
<Button fx:id="editTask" mnemonicParsing="false" onAction="#editTasksOnA" text="Edit" />
<Button fx:id="deleteTask" mnemonicParsing="false" onAction="#deleteTasksOnA" text="Delete" />
<Button fx:id="runTasks" mnemonicParsing="false" onAction="#runTasksOnA" text="Run" />
<Label fx:id="numRunsLab" text="Iterations:" />
<TextField fx:id="numRuns" prefHeight="39.0" prefWidth="90.0" promptText="1" />
<Button fx:id="clearTasks" mnemonicParsing="false" onAction="#clearTasksOnA" text="Clear Tasks" />
<Button fx:id="saveTasks" mnemonicParsing="false" onAction="#saveTasksOnA" text="Save" />
<Button fx:id="openTasks" mnemonicParsing="false" onAction="#openTasksOnA" text="Open" />
</children>
</HBox>
</top>
<right>
<VBox alignment="CENTER" prefHeight="945.0" prefWidth="89.0">
<children>
<Button fx:id="moveToTop" mnemonicParsing="false" text="Move Top" />
<Button fx:id="moveUp" mnemonicParsing="false" text="Move Up" />
<Button fx:id="moveDown" mnemonicParsing="false" text="Move Down" />
<Button fx:id="moveToBottom" mnemonicParsing="false" text="Move Bottom" />
</children>
</VBox>
</right>
</BorderPane>
NTB.fxml:
<?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.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.stage.Stage?>
<Stage fx:id="window" fx:controller="com.test.NTB" xmlns="http://javafx.com/javafx/13" xmlns:fx="http://javafx.com/fxml/1" >
<BorderPane >
<center>
<VBox alignment="CENTER">
<HBox alignment="CENTER">
<padding>
<Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
</padding>
<VBox alignment="CENTER">
<children>
<Label fx:id="nameLabel" text="Name: " />
</children>
</VBox>
<VBox alignment ="CENTER">
<children>
<TextField fx:id="nameField" promptText="Name..." />
</children>
</VBox>
</HBox>
<HBox alignment="CENTER">
<padding>
<Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
</padding>
<VBox alignment="CENTER">
<children>
<Label fx:id="xLabel" text="X Coord: " />
</children>
</VBox>
<VBox>
<children>
<TextField fx:id="xField" promptText="0.0" />
</children>
</VBox>
</HBox>
<HBox alignment="CENTER">
<padding>
<Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
</padding>
<VBox alignment="CENTER">
<children>
<Label fx:id="yLabel" text="Y Coord: " />
</children>
</VBox>
<VBox>
<children>
<TextField fx:id="yField" promptText="0.0" />
</children>
</VBox>
</HBox>
<HBox alignment="CENTER">
<padding>
<Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
</padding>
<VBox alignment="CENTER">
<children>
<Label fx:id="buttonLabel" text="Button: " />
</children>
</VBox>
<VBox>
<children>
<ChoiceBox fx:id="buttonBox" value="MouseButton.PRIMARY" />
</children>
</VBox>
</HBox>
<HBox alignment="CENTER">
<padding>
<Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
</padding>
<VBox alignment="CENTER">
<children>
<Label fx:id="keyLabel" text="Key: " />
</children>
</VBox>
<VBox>
<children>
<TextField fx:id="keyField" maxWidth="25.0" promptText="A" />
</children>
</VBox>
</HBox>
<HBox alignment="CENTER">
<padding>
<Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
</padding>
<VBox alignment="CENTER">
<children>
<Label fx:id="descriptionLabel" text="Description: " />
</children>
</VBox>
<VBox>
<children>
<TextArea fx:id="descriptionArea" promptText="Enter description..." maxWidth="150" maxHeight="100" />
</children>
</VBox>
</HBox>
<HBox alignment="CENTER">
<padding>
<Insets top="20.0" right="10.0" bottom="0.0" left="5.0" />
</padding>
<VBox alignment="CENTER">
<children>
<Label fx:id="delayLabel" text="Delay: " />
</children>
</VBox>
<VBox>
<children>
<TextField fx:id="delayField" promptText="0" />
</children>
</VBox>
</HBox>
</VBox>
</center>
<bottom>
<HBox alignment="CENTER">
<Button fx:id="doneButton" onAction="#doneButtonOnA" text="Done" />
<Button fx:id="cancelButton" onAction="#cancelButtonOnA" text="Cancel" />
</HBox>
</bottom>
</BorderPane>
</Stage>
Controller.java:
package com.test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Scanner;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseButton;
import javafx.stage.FileChooser;
import javafx.stage.Window;
public class Controller extends Test implements Initializable
{
@FXML private TableView<Task> table;
@FXML private TableColumn<Task, Integer> orderCol;
@FXML private TableColumn<Task, String> nameCol;
@FXML private TableColumn<Task, Double> xCol;
@FXML private TableColumn<Task, Double> yCol;
@FXML private TableColumn<Task, MouseButton> buttonCol;
@FXML private TableColumn<Task, String> keyCol;
@FXML private TableColumn<Task, String> descriptionCol;
@FXML private TableColumn<Task, Long> delayCol;
@FXML private TextField numRuns;
@FXML private Window nTB;
@FXML private NTB nTBController;
@Override
public void initialize(URL url, ResourceBundle resources)
{
numRuns.textProperty().addListener((observable, oldValue, newValue) -> {
if(newValue.matches("\\d*")) return;
numRuns.setText(newValue.replaceAll("[^\\d]", ""));
});
orderCol.setCellValueFactory(column-> new ReadOnlyObjectWrapper<Integer>(table.getItems().indexOf(column.getValue()) + 1));
nameCol.setCellValueFactory(new PropertyValueFactory<Task, String>("name"));
xCol.setCellValueFactory(new PropertyValueFactory<Task, Double>("x"));
yCol.setCellValueFactory(new PropertyValueFactory<Task, Double>("y"));
buttonCol.setCellValueFactory(new PropertyValueFactory<Task, MouseButton>("button"));
keyCol.setCellValueFactory(new PropertyValueFactory<Task, String>("keyCode"));
descriptionCol.setCellValueFactory((new PropertyValueFactory<Task, String>("description")));
delayCol.setCellValueFactory(new PropertyValueFactory<Task, Long>("delay"));
table.getItems().setAll(list);
}
@FXML private void newTaskDisplay()
{
nTBController.display();
table.getItems().setAll(list);
}
Test.java:
package com.test;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class Test extends Application {
private static Scene scene;
protected static Stage stage;
protected static ObservableList<Task> list = FXCollections.observableArrayList();
@Override
public void start(Stage primStage) throws IOException {
stage = primStage;
scene = new Scene(loadFXML("Test"), 640, 480);
scene.getStylesheets().add(getClass().getResource("Test.css").toExternalForm());
stage.setScene(scene);
stage.show();
}
static void setRoot(String fxml) throws IOException {
scene.setRoot(loadFXML(fxml));
}
private static Parent loadFXML(String fxml) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(Test.class.getResource(fxml + ".fxml"));
return fxmlLoader.load();
}
public static void main(String[] args) {
launch();
}
}
Error on run:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:119)
at java.base/java.lang.reflect.Method.invoke(Method.java:577)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:577)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1081)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: javafx.fxml.LoadException: Element does not define a default property.
/C:/Users/dylan/Desktop/testing/test/target/classes/com/test/NTB.fxml:133
/C:/Users/dylan/Desktop/testing/test/target/classes/com/test/Test.fxml:15
at javafx.fxml/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2621)
at javafx.fxml/javafx.fxml.FXMLLoader$Element.set(FXMLLoader.java:187)
at javafx.fxml/javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:798)
at javafx.fxml/javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2838)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2557)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
at javafx.fxml/javafx.fxml.FXMLLoader$IncludeElement.constructValue(FXMLLoader.java:1154)
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)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
at com.test/com.test.Test.loadFXML(Test.java:36)
at com.test/com.test.Test.start(Test.java:23)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
... 1 more
Exception running application com.test.Test
Tag to include in Test.fxml:
<fx:include fx:id="NTB" source="NTB.fxml" />
If there's any other info that would help with this please ask and I'd be happy to provide.
I'm also not dead set on having this be the final structure of this program so if this is unnecessarily difficult to do and there's a simpler way to accomplish the same thing please let me know. I'm new to using fxml with JavaFX so I'm not sure of the best ways to do things quite yet.
Here is the error:
Caused by: javafx.fxml.LoadException: Element does not define a default property.
/C:/Users/dylan/Desktop/testing/test/target/classes/com/test/NTB.fxml:133
/C:/Users/dylan/Desktop/testing/test/target/classes/com/test/Test.fxml:15
This error (specifically) is not about the location of the fx:include
element. The problem is an element in the NTB.fxml
file does not define a default property. And it says the error is occurring on line 133
of the FXML file. That line is the closing </BorderPane>
tag. And this makes sense, because the parent element is defining a Stage
, which indeed does not define a default property.
When you have something like this:
<VBox>
<Label/>
</VBox>
That puts the Label
in the children list of the VBox
. The reason this works is because Pane
is annotated with @DefaultProperty("children")
. That annotation is @Inherited
, so VBox
has the same annotation. Thus, the elements that are directly inside the <VBox>
element are applied to the children
property. If that annotation wasn't present, then you'd need to do:
<VBox>
<children>
<Label/>
</children>
</VBox>
The Stage
class does not have a @DefaultProperty
annotation. Neither do any of its superclasses. That means you can't just place elements directly inside a <Stage>
element. You have to tell FXML which property you're trying to set.
And that leads to another problem. You can't place a BorderPane
in a Stage
. You would need to wrap that as the root of a Scene
first. Something like:
<Stage>
<scene>
<Scene width="-1" height="-1">
<!-- The Scene class is annotated with DefaultProperty("root") -->
<BorderPane>
<!-- your stuff -->
</BorderPane>
</Scene>
</scene>
</Stage>
Stage
Unfortunately, this leads to yet another problem. You are trying to embed NBT.fxml
inside another FXML file. You can't place a Stage
inside another Stage
(let alone another Node
). You either need to rethink your design or you need to define the root element of NBT.fxml
to be some kind of Node
instead of a Stage
.
If you decide to continue using fx:include
here (meaning you changed the root element to be a type of Node
), then keep in mind that BorderPane
inherits its @DefaultProperty
annotation from Pane
. That means its default property is children
. Adding a node directly to the children of a border pane should not be done; that child would not be managed properly. Make sure to move the fx:include
element to be inside a <top>
, <left>
, <bottom>
, <right>
, or <center>
element.
Stage
(Untested)If you want to keep the root element of NBT.fxml
as a Stage
, then there might be something that can work. I have not tried this though, so I don't know if it's legal. Try putting the fx:include
inside an fx:define
element:
<BorderPane ...>
<fx:define>
<fx:include fx:id="nTB" source="NTB.fxml" />
</fx:define>
<!-- Your stuff -->
</BorderPane>
This assumes you fixed the default property issue in NBT.fxml
.
That said, if your NBT.fxml
file defines a Stage
, then honestly I think it's better to just not fx:include
it. Simply load that FXML file inside the controller of Test.fxml
only when you need to display that new window. In other words:
@FXML
private void newTaskDisplay() throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("NBT.fxml"));
Stage stage = loader.load();
stage.show();
}