JavaFx: parent.lookup returns null - java

I use osgi+cdi and I have the following code:
Parent parent=null;
FXMLLoader fxmlLoader=getFxmlLoader();
try {
parent = (Parent)fxmlLoader.load(getFxmlStream("tasklist.fxml"));
} catch (IOException ex) {
Logger.getLogger(TestGoView.class.getName()).log(Level.SEVERE, null, ex);
}
ComboBox comboBox=(ComboBox) parent.lookup("#testComboBox");
if (comboBox==null){
System.out.println("COMBOBOX NULL");
}else{
System.out.println("COMBOBOX NOT NULL");
}
And I have the following tasklist.fxml
<VBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="440.0" prefWidth="757.0" xmlns="http://javafx.com/javafx/8.0.60-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.techsenger.testgo.core.adm.task.list.TaskDirListController">
<children>
<HBox>
<children>
<ToolBar maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" nodeOrientation="RIGHT_TO_LEFT" HBox.hgrow="SOMETIMES">
<items>
<ComboBox fx:id="testComboBox" maxWidth="1.7976931348623157E308" nodeOrientation="LEFT_TO_RIGHT" />
</items>
</ToolBar>
</children>
</HBox>
</children>
</VBox>
However parent.lookup("#testComboBox") returns null. How to explain it? I've checked the name of ID several times.

Instead of using a lookup, which will only work after the scene has been rendered, you can put the logic you need in your controller class. You can inject elements from the FXML file into the controller class by annotating them #FXML.
public class TaskDirListController {
#FXML
private ComboBox<...> testComboBox ;
public void initialize() {
System.out.println(testComboBox);
}
// ...
}
Lookups are generally not robust, and I would recommend avoiding using them. If you really need to access something defined in the FXML file from a class other than the controller, the first thing to do is to consider reorganizing things so that you don't need to do this: it really indicates that your overall design is wrong.
If you really need this for some reason, it's better to use the FXMLLoader's namespace than a lookup:
Parent parent=null;
FXMLLoader fxmlLoader=getFxmlLoader();
try {
parent = (Parent)fxmlLoader.load(getFxmlStream("tasklist.fxml"));
ComboBox<?> comboBox = (ComboBox<?>) fxmlLoader.getNamespace().get("testComboBox");
System.out.println(comboBox);
} catch (IOException ex) {
Logger.getLogger(TestGoView.class.getName()).log(Level.SEVERE, null, ex);
}

It is because you are trying to use lookup before showing the parent on the screen.
Pane root = FXMLLoader.load(getClass().getResource("tasklist.fxml"));
System.out.println(root.lookup("#testComboBox")); //returns null
primaryStage.setScene(new Scene(root));
primaryStage.show();
System.out.println(root.lookup("#testComboBox")); //returns
// ComboBox[id=testComboBox, styleClass=combo-box-base combo-box]

Related

fx:include with "resources" throws MissingResourceException but works in Java Code

I'm trying to use the resource tag inside fx:include in a FXML file.
What I don't understand is, that loading the resource bundle manually with ResourceBundle.getBundle() works completely fine.
I already tried a lot of variants in the fxml like:
"lang_challenges"
"wand555/github/io/challengesreworkedgui/lang_challenges"
package wand555.github.io.challengesreworkedgui;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;
public class ChallengeApplication extends Application {
#Override
public void start(Stage stage) throws IOException {
ResourceBundle.clearCache();
ResourceBundle bundle = new ResourceBundleWrapper(ResourceBundle.getBundle("wand555/github/io/challengesreworkedgui/lang_challenges"));
System.out.println(bundle.getString("challenge.name")); // outputs "abc"
FXMLLoader loader = new FXMLLoader(ChallengeApplication.class.getResource("overview.fxml"), bundle);
Parent root = loader.load();
Scene scene = new Scene(root, 1000, 1000);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
// this class effectively does nothing, but it will be loaded by the
// application class loader
// instead of the system class loader.
private static class ResourceBundleWrapper extends ResourceBundle {
private final ResourceBundle bundle;
ResourceBundleWrapper(ResourceBundle bundle) {
this.bundle = bundle;
}
#Override
protected Object handleGetObject(String key) {
return bundle.getObject(key);
}
#Override
public Enumeration<String> getKeys() {
return bundle.getKeys();
}
#Override
public boolean containsKey(String key) {
return bundle.containsKey(key);
}
#Override
public Locale getLocale() {
return bundle.getLocale();
}
#Override
public Set<String> keySet() {
return bundle.keySet();
}
}
}
overview.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<AnchorPane prefHeight="500.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="wand555.github.io.challengesreworkedgui.controllers.OverviewController">
<children>
<VBox>
<children>
<StackPane alignment="CENTER_LEFT">
<children>
<Button fx:id="exportButton" mnemonicParsing="false" onAction="#onExport" text="Export" />
</children>
</StackPane>
<HBox prefHeight="100.0" prefWidth="200.0" spacing="25.0">
<children>
<fx:include fx:id="challengesOverview" source="challenges/challenges_overview.fxml" resources="lang_challenges" charset="utf-8"/>
<Separator orientation="VERTICAL" prefHeight="200.0" />
<fx:include source="goals/goal_overview.fxml" />
<Separator orientation="VERTICAL" prefHeight="200.0" />
</children>
</HBox>
</children>
</VBox>
</children>
</AnchorPane>
The lang_challenges.properties contains a single key-value pair
challenge.name=abc
The `lang_challenges_de.properties' has the same content
challenge.name=abc
And this is the error message I'm getting
Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at javafx.graphics#19/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:465)
at javafx.graphics#19/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1082)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics#19/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
at javafx.graphics#19/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: javafx.fxml.LoadException:
/Users/felixnaumann/Documents/ChallengesReworked/ChallengesReworkedGUI/target/classes/wand555/github/io/challengesreworkedgui/overview.fxml:21
at javafx.fxml#19/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2707)
at javafx.fxml#19/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2685)
at javafx.fxml#19/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
at javafx.fxml#19/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2516)
at challenges.reworked.gui/wand555.github.io.challengesreworkedgui.ChallengeApplication.start(ChallengeApplication.java:22)
at javafx.graphics#19/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
at javafx.graphics#19/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
at javafx.graphics#19/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics#19/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
at javafx.graphics#19/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Caused by: java.util.MissingResourceException: Can't find bundle for base name lang_challenges, locale de_DE
at java.base/java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:2045)
at java.base/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1683)
at java.base/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1575)
at java.base/java.util.ResourceBundle.getBundle(ResourceBundle.java:1280)
at javafx.fxml#19/javafx.fxml.FXMLLoader$IncludeElement.processAttribute(FXMLLoader.java:1100)
at javafx.fxml#19/javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:230)
at javafx.fxml#19/javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:755)
at javafx.fxml#19/javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2808)
at javafx.fxml#19/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2634)
... 9 more
Exception running application wand555.github.io.challengesreworkedgui.ChallengeApplication
Whew, finally figured it out after digging deep into the source code of ResourceBundle and ClassLoader.
How to fix it:
Really easy way:
Put your .properties files at the root of the resources folder. Then use it inside fxml
<fx:include source="second.fxml" resources="second_bundle"/>
and then everything should work fine.
However this approach is not suitable for larger projects which subdivide the resource bundles into different packages.
Using sub-packages in resources package
Give the fully qualified path name in the resources tag.
So for example if your package structure from src is com/example/demo/ (also in the resources folder) then use
<fx:include source="second.fxml" resources="com/example/demo/second_bundle"/>
But we are not done yet. You need to open the package to all modules in the module-info.java, explicitly using
opens com.example.demo to javafx.fxml;
does not work.
Instead you need to write
opens com.example.demo;
My two cents
Honestly to me this sounds like a bug.
I debugged the entire loading process and when the second_bundle is loaded from inside the fxml file, the caller module is javafx.fxml. And as the java doc for getResourceAsStream (which is internally called when loading) states:
A package name is derived from the resource name. If the package name is a package in the module then the resource can only be located by the caller of this method when the package is open to at least the caller's module. If the resource is not in a package in the module then the resource is not encapsulated.
So in theory opening your package to just javafx.fxml should work, but it doesn't...
Full demo project
This demo project uses sub-packages.
Project structure:
HelloApplication:
public class HelloApplication extends Application {
#Override
public void start(Stage stage) throws IOException {
ResourceBundle bundle = new ResourceBundleWrapper(ResourceBundle.getBundle("test_bundle"));
System.out.println(bundle.getString("first.button")); // outputs "English/Deutsch"
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("first.fxml"), bundle);
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
// this class effectively does nothing, but it will be loaded by the
// application class loader
// instead of the system class loader.
private static class ResourceBundleWrapper extends ResourceBundle {
private final ResourceBundle bundle;
ResourceBundleWrapper(ResourceBundle bundle) {
this.bundle = bundle;
}
#Override
protected Object handleGetObject(String key) {
return bundle.getObject(key);
}
#Override
public Enumeration<String> getKeys() {
return bundle.getKeys();
}
#Override
public boolean containsKey(String key) {
return bundle.containsKey(key);
}
#Override
public Locale getLocale() {
return bundle.getLocale();
}
#Override
public Set<String> keySet() {
return bundle.keySet();
}
}
}
first.fxml:
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml"
fx:controller="com.example.demo.HelloController">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
<Label fx:id="welcomeText"/>
<Button text="%first.button" onAction="#onHelloButtonClick"/>
<fx:include source="second.fxml" resources="com/example/demo/second_bundle"/>
</VBox>
second.fxml:
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
<Label fx:id="welcomeText"/>
<Button text="%second.button"/>
</VBox>
test_bundle.properties:
first.button=English
second_bundle.properties:
second.button=Hello
module-info.java:
module com.example.demo {
requires javafx.controls;
requires javafx.fxml;
opens com.example.demo;
exports com.example.demo;
}

JavaFX 8: Custom controller from an inner class

The Problem
I am getting a ClassNotFoundException when trying to use the custom controller inside Joystick.java.
Here is my file hierarchy:
--view
----MainWindow.java
----mainWindow.fxml
----Joystick
------Joystick.java
------joystick.fxml
In mainWindow.fxml, I have the lines:
<?import view.Joystick.Joystick?>
...
<Joystick fx:id="manualJsk" layoutX="459.0" layoutY="195.0" />
I want to display my custom controller, but I keep getting the ClassNotFoundException, despite importing it.
Interestingly, everything works if I move the file to the view package:
--view
----MainWindow.java
----mainWindow.fxml
----Joystick.java
----Joystick
------joystick.fxml
... which makes me think the import is bad. Why could that be?
The Exception
java.lang.ClassNotFoundException: view.Joystick$Joystick
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at javafx.fxml/javafx.fxml.FXMLLoader.loadTypeForPackage(FXMLLoader.java:2931)
at javafx.fxml/javafx.fxml.FXMLLoader.loadType(FXMLLoader.java:2920)
at javafx.fxml/javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2861)
... 15 more
Edit:
Joystick Code:
public class Joystick extends Pane {
public Joystick() {
super();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("joystick.fxml"));
loader.setRoot(this);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
}
joystick.fxml
<fx:root xmlns:fx="http://javafx.com/fxml" type="javafx.scene.layout.Pane">
<children>
<Button text="Click Me"/>
</children>
</fx:root>

Explain why FXML objects were null

I came across a problem in my code that all the objects that were related to the FXML file for a controller class were null even though the styling from the FXML was working and all the fx:id tags were the same. Here is the FXML code:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
alignment="center"
spacing="10"
prefHeight="750"
prefWidth="1000"
style="-fx-background-color: lightslategray">
<padding><Insets top="0" bottom="10" left="10" right="10"></Insets></padding> <!-- Set the padding at 10px for each side of the window -->
<Label fx:id="titleLabel" style="-fx-font-weight: bold; -fx-font-size: 32;" wrapText="true" text="Deck Title"/>
<HBox spacing="10">
<Button fx:id="backButton" text="Back" prefWidth="50"/>
<ProgressBar fx:id="progressIndicator" GridPane.columnIndex="0" GridPane.rowIndex="0" prefWidth="920" progress="0.0"/>
</HBox>
<HBox spacing="20">
<Label fx:id="qLabel" style="-fx-background-color: white; -fx-border-color: black" prefWidth="480" prefHeight="400" wrapText="true"/>
<Label fx:id="aLabel" style="-fx-background-color: white; -fx-border-color: black; -fx-cursor: hand" prefWidth="480" prefHeight="400" wrapText="true" text="Click here to reveal the answer" onMouseClicked="#updateAnswer"/>
</HBox>
<HBox spacing="780">
<Button fx:id="incorrectButton" text="Incorrect" prefWidth="100"/>
<Button fx:id="correctButton" text="Correct" prefWidth="100"/>
</HBox>
</VBox>
Here is the code for the controller class:
public class openCardsController {
#FXML Button backButton;
#FXML ProgressBar progressIndicator;
#FXML Label qLabel;
#FXML Label aLabel;
#FXML Label titleLabel;
#FXML Button incorrectButton;
#FXML Button correctButton;
public void openCards() throws IOException, ParseException {
Stage window = Main.getStage();
window.setWidth(1000);
window.setHeight(750);
// Had to swap Parent root = FXMLLoader.load(getClass().getResource("./mainPage.fxml")); for the following lines
File file = new File(System.getProperty("user.dir") + "/src/flashcardApplication/openCardsPage.fxml");
FXMLLoader loader = new FXMLLoader(file.toURI().toURL());
loader.setController(this);
VBox root = loader.load();
backButton.setOnAction(e -> {
try {
backButtonPressed();
} catch (IOException ignored) {}
});
incorrectButton.setOnAction(e -> incorrect());
correctButton.setOnAction(e -> correct());
window.setTitle("Flashcard Application - Open Cards");
Scene mainMenuScene = new Scene(root, 1000, 750);
window.setScene(mainMenuScene);
int deckid = chooseCards();
String fileURL = "ftp://appuser:pass123.#127.0.0.1/decks/" + Integer.toString(deckid) + ".json";
URL url = new URL(fileURL); // Lines 43 to 45 come from https://www.javaworld.com/article/2073325/java-ftp-client-libraries-reviewed.html
URLConnection urlc = url.openConnection();
InputStream inputStream = urlc.getInputStream();
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject)jsonParser.parse(new InputStreamReader(inputStream, "UTF-8"));
String title = (String) jsonObject.get("name");
titleLabel.setText(title);
}
I had to remove the attribute fx:controller="flashcardApplication.openCardsController from the FXML file and I had to replace the line Parent root = FXMLLoader.load(getClass().getResource("./mainPage.fxml")); with the following lines:
File file = new File(System.getProperty("user.dir") + "/src/flashcardApplication/openCardsPage.fxml");
FXMLLoader loader = new FXMLLoader(file.toURI().toURL());
loader.setController(this);
Please could someone explain why I had to use the different solution because I used the one line solution in two other FXML files and their corresponding controller classes without any issues
The #FXML-annotated fields are initialized in the controller when the FXML is loaded. By default, the FXMLLoader creates an instance of the class specified by the fx:controller attribute, and uses it as the controller.
Consequently, in your original code, the controller is not the current instance of OpenCardsController on which openCards() is being invoked, but is the new instance of the same class. Thus the #FXML-annotated fields are not initialized in the current instance, but in the new instance that is created by the FXMLLoader.
By removing the fx:controller attribute, and explicitly setting the controller to the exact object you need (the current instance of OpenCardsController), you achieve what you need: the controller is now the current instance and the FXML-annotated fields are initialized in that object.
Note that it's a bit unusual to load the FXML file from the controller itself. The typical approach is to load the FXML from some other code, and display the resulting UI; the controller is usually a separate object. It may be more natural (and easier to maintain in the long run) if you refactor your code so that the FXML is loaded from somewhere else. (This is really a separation of concerns and single-responsibility issue: the controller should only be responsible for processing user input from the corresponding FXML file; it should not be responsible for loading the FXML as well.)

NullPointer Exception thrown with JavaFX

My application is throwing a NullPointer exception when I call the variable empName.
ResultSet result = stmnt.executeQuery("select FirstName, LastName from emp_info where EmployeeID "
+ "= '" + empID + "'");
// while(result.next()){
// empName.setText("result.getString(1));
// }
empName.setText("asdf");
rootLayout.setCenter(controlData);
connection.close();
}
}
It should be able to run fine since I initialize the Text variable like so:
#FXML
public Text empName;
Also when I use scenebuilder, it sometimes shows the fx:id empName but when I exit out of it and reopen it doesn't show it. I think that's where the problem is. My xml file is:
<AnchorPane prefHeight="300.0" prefWidth="500.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="studentempsignin.MainPage_Controller">
<children>
<BorderPane prefHeight="300.0" prefWidth="500.0">
<center>
<Text fx:id="empName" strokeType="OUTSIDE" strokeWidth="0.0" text="Text" BorderPane.alignment="CENTER" />
</center>
</BorderPane>
</children>
</AnchorPane>
The exception I get is:
SEVERE: null
java.lang.NullPointerException
at studentempsignin.MainPage_Controller.signingIn(MainPage_Controller.java:190)
at studentempsignin.SignIn_Controller.lambda$0(SignIn_Controller.java:66)
at studentempsignin.SignIn_Controller$$Lambda$143/575703892.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
Edit:
The method empIDAccess is being called when I click the signIn button:
signInBtn.setOnAction((e) -> {
try {
//used dbaseDriver...idk why
// DBaseDriver connect = new DBaseDriver("jdbc:mysql://localhost:3306/AUStudentEmployees",
// "kheneahm", "kennygoham");
String empID = empIDField.getText();
MainPage_Controller empIDAccess = new MainPage_Controller();
empIDAccess.signingIn(empID, invalidID, signInBtn);
} catch (Exception ex) {
Logger.getLogger(SignIn_Controller.class.getName()).log(Level.SEVERE, null, ex);
}
});
You're creating a new controller instance. The FXMLLoader creates a controller instance and initializes the #FXML-annotated fields in that instance, when you load the FXML file. Those fields won't be initialized in the new instance you create (and even if they were, they wouldn't refer to the same objects displayed in the UI).
You need to get a reference to the controller that is created when you load the FXML.

Error creating a custom FXML loader in Spring

I've been trying to move my JavaFx application to Spring to make use of dependency injecton. The project has become too big to move items between classes manually.
The code does not show any red error highlights on my netbeans IDE, but when I run I keep getting this error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'homeController' defined in class wakiliproject.controllerinjection.SampleAppFactory: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public wakiliproject.controllerinjection.controllers.HomeController wakiliproject.controllerinjection.SampleAppFactory.homeController() throws java.io.IOException] threw exception; nested exception is javafx.fxml.LoadException: Base location is undefined.
I have it like this:
public class SampleApp extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage stage) throws Exception {
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext(SampleAppFactory.class);
Group box = new Group();
HomeController homeController = context.getBean(HomeController.class);
box.getChildren().add(homeController.getView());
Scene scene = new Scene(box, 600, 200);
stage.setScene(scene);
stage.setTitle("JFX2.0 Sprung");
stage.show();
}
}
--
#Configuration
public class SampleAppFactory {
#Bean
public HomeController homeController() throws IOException {
return (HomeController) loadController("/resources/fxml/Home.fxml");
}
protected Object loadController(String url) throws IOException {
InputStream fxmlStream = null;
try {
fxmlStream = getClass().getResourceAsStream(url);
FXMLLoader loader = new FXMLLoader();
loader.load(fxmlStream);
return loader.getController();
} finally {
if (fxmlStream != null) {
fxmlStream.close();
}
}
}
}
--
public class HomeController {
#FXML
private AnchorPane view;
public AnchorPane getView() {
return view;
}
}
An extract of the FXML file looks something like this:
<?xml version="1.0" encoding="UTF-8"?>
<AnchorPane fx:id="view" prefHeight="654.0" prefWidth="900.0" styleClass="AnchorPane" visible="true" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="wakiliproject.controllerinjection.controllers.HomeController">
<children>
<Pane id="wrapperPane" prefHeight="600.0" prefWidth="700.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Pane id="top" layoutX="-1.0" layoutY="3.0" prefWidth="879.0" styleClass="appNav" visible="true">
<children>
<HBox id="HBox" alignment="CENTER" layoutX="12.0" layoutY="6.0" spacing="0.0">
<children>
<Label prefHeight="32.0" prefWidth="32.0" styleClass="titleBarHome" />
<Label prefHeight="32.0" prefWidth="32.0" styleClass="titleBarPublisher" />
</children>
</HBox>
It looks like you need to set the location of your FXML file on the FXMLLoader. This can be the case if, for example, your FXML file requires resolving relative locations. Using the FXMLLoader.load(URL) method does not set the location. Try
protected Object loadController(String url) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource(url));
loader.load();
return loader.getController();
}
instead of the current implementation you have.
Incidentally, have you looked at afterburner.fx as a (much more lightweight) alternative to Spring for dependency injection in JavaFX?

Categories

Resources