JavaFX Netbeans FXML not found - javafx

Hello everyone i am learning javafx and i am having issue to run simple basic program of hello world i know that javafx works in MVC type structure which fxml,mainclass, and controller so what i am doing is i just created the first program in JavaFX in which 3 things were there a HelloWorld.Java , HelloWorld.fxml and HelloWorldController.java and creating a com.bean package for HelloWorld.java and com.gui for HelloWorld.fxml and com.controller for HelloWorldController.java but i am facing an issue while i am running it it shows an exception that fxml is not loaded a location is required.....please help i also bild and cleaned it many time but not working.....
HelloWorld.java
package com.bean;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/*
* 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.
*/
/**
*
* #author Love Poet
*/
public class HelloWorld extends Application{
#Override
public void start(Stage stage) throws Exception {
Parent root=FXMLLoader.load(this.getClass().getResource("com/gui/HelloWorld.fxml"));
Scene scene=new Scene(root);
stage.setTitle("Hellow World Example");
stage.setScene(scene);
stage.show();
}
public static void main(String args[])
{
launch(args);
}
}
HelloWorldController.java
package com.controller;
/**
* Sample Skeleton for 'HelloWorld.fxml' Controller Class
*/
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
public class HelloWorldController implements Initializable{
#FXML // fx:id="button"
private Button button; // Value injected by FXMLLoader
#FXML // fx:id="label"
private Label label; // Value injected by FXMLLoader
#FXML
void handleButtonAction(ActionEvent event) {
label.setText("Hello World !");
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
}
HelloWorld.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.*?>
<?import com.controller.*?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="HelloWorldController">
<children>
<Button fx:id="button" layoutX="47.0" layoutY="129.0" onAction="#handleButtonAction" prefHeight="25.0" prefWidth="211.0" text="Click Me!" />
<Label fx:id="label" layoutX="35.0" layoutY="35.0" minHeight="16" minWidth="69" prefHeight="45.0" prefWidth="274.0" />
</children>
</AnchorPane>
for this i am using netbeans my structure of doing this is :-
This is an image of netbeans project structure

You're using a class in the com.bean to get the resource, which means using the relative path com/gui/HelloWorld.fxml creates a url that would point to the HelloWorld.fxml in the com.bean.com.gui package.
In this case you either need to use the ClassLoader with the same relative path:
this.getClass().getClassLoader().getResource("com/gui/HelloWorld.fxml")
or use a path relative to the classpath root
this.getClass().getResource("/com/gui/HelloWorld.fxml")

Related

Share the same reusable FXML component in multiple views

I have a FXML view that contains a TabView with multiple tabs.
Every Tab has it's own FXML component + controller.
I would like all tabs to report progress via a component defined defined in the main view.
I know that I can inject child controllers into the main controller via FXML.
But to my current understanding, I need to access the parent controller inside my child controllers since the component is located in the main view.
I can also access the child controllers inside the initialize method of my main view. If I follow this path, I would need to modify the child controllers to set the shared component.
This is suboptimal, since the child components would be dependent on a main view that is performing those changes.
I created a MWE to illustrate the dilemma.
The question in short:
How can I report progress of Service1 and Service2 to the progressAndStatusGrid in the main view?
Callenge in short:
Make this application not throw a NPE and report progress to the progress component ;)
MWE:
Launcher:
package org.example;
public class Launcher {
public static void main(final String[] args) {
SimpleApplication.main(args);
}
}
Application:
package org.example;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class SimpleApplication extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/MainView.fxml"));
#SuppressWarnings("unused")
MainViewController controller = fxmlLoader.getController();
final Parent root = fxmlLoader.load();
final Scene scene = new Scene(root);
primaryStage.setTitle("Hello World");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
MainController:
package org.example;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.GridPane;
import java.net.URL;
import java.util.ResourceBundle;
public class MainViewController implements Initializable {
#FXML
GridPane progressAndStatusGrid;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
}
MainView:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane prefHeight="150.0" prefWidth="350.0" xmlns="http://javafx.com/javafx/17.0.2-ea"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.MainViewController">
<padding>
<Insets top="4" right="4" bottom="4" left="4"/>
</padding>
<top>
</top>
<center>
<TabPane>
<Tab text="tab1" closable="false">
<fx:include fx:id="tab1" source="Tab1View.fxml"/>
</Tab>
<Tab text="tab2" closable="false">
<fx:include fx:id="tab2" source="Tab2View.fxml"/>
</Tab>
</TabPane>
</center>
<bottom>
<fx:include fx:id="progressAndStatusGrid"
source="ProgressAndStatusGridComponent.fxml"/>
</bottom>
</BorderPane>
"Shared" componentController:
package org.example;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.HBox;
import java.net.URL;
import java.util.ResourceBundle;
public class ProgressAndStatusGridComponentController implements Initializable {
#FXML
ProgressBar progressBar;
#FXML
HBox progressStatusBox;
#FXML
Label progressLabel;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
}
"Shared" componentView:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.layout.*?>
<GridPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.example.ProgressAndStatusGridComponentController"
hgap="4" vgap="4">
<padding>
<Insets top="4" right="4" bottom="4" left="4"/>
</padding>
<fx:define>
<ColumnConstraints fx:id="colConstraints2" percentWidth="100"/>
</fx:define>
<columnConstraints>
<fx:reference source="colConstraints2"/>
<fx:reference source="colConstraints2"/>
</columnConstraints>
<ProgressBar fx:id="progressBar" GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<HBox fx:id="progressStatusBox" alignment="CENTER" spacing="4" GridPane.columnIndex="1" GridPane.rowIndex="0">
<padding>
<Insets top="4" right="4" bottom="4" left="4"/>
</padding>
<Label fx:id="progressLabel"/>
</HBox>
</GridPane>
Tab1Controller:
package org.example;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import java.net.URL;
import java.util.ResourceBundle;
public class Tab1Controller implements Initializable {
#FXML
Button button1;
Service1 service1 = new Service1();
// How to get a reference, that is already initialized?
#FXML
ProgressAndStatusGridComponentController progressAndStatusGridComponentController;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
button1.disableProperty().bind(service1.runningProperty());
}
public void handleButtonClick(ActionEvent actionEvent) {
service1.cancel();
service1.reset();
progressAndStatusGridComponentController.progressBar.progressProperty().bind(service1.progressProperty());
progressAndStatusGridComponentController.progressLabel.textProperty().bind(service1.messageProperty());
service1.start();
}
}
Tab1View:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.example.Tab1Controller">
<center>
<Button fx:id="button1" text="Start Background Progress #1" onAction="#handleButtonClick"/>
</center>
</BorderPane>
Tab2Controller:
package org.example;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import java.net.URL;
import java.util.ResourceBundle;
public class Tab2Controller implements Initializable {
#FXML
Button button2;
Service2 service2 = new Service2();
// How to get a reference, that is already initialized?
#FXML
ProgressAndStatusGridComponentController progressAndStatusGridComponentController;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
button2.disableProperty().bind(service2.runningProperty());
}
public void handleButtonClick(ActionEvent actionEvent) {
service2.cancel();
service2.reset();
progressAndStatusGridComponentController.progressBar.progressProperty().bind(service2.progressProperty());
progressAndStatusGridComponentController.progressLabel.textProperty().bind(service2.messageProperty());
service2.start();
}
}
Tab2View:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.example.Tab2Controller">
<center>
<Button fx:id="button2" text="Start Background Progress #2" onAction="#handleButtonClick"/>
</center>
</BorderPane>
Service1:
package org.example;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
public class Service1 extends Service<Void> {
static final int workLoad = 100;
#Override
protected Task<Void> createTask() {
return new Task<>() {
#Override
protected Void call() throws Exception {
updateMessage("Starting Task #1..");
for (int i = 0; i < workLoad; i++) {
Thread.sleep(200);
updateProgress(i, workLoad);
updateMessage(i + " elements done");
}
updateMessage("Task #1 done!");
return null;
}
};
}
}
Service2:
package org.example;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
public class Service2 extends Service<Void> {
static final int workLoad = 100;
#Override
protected Task<Void> createTask() {
return new Task<>() {
#Override
protected Void call() throws Exception {
updateMessage("Starting Task #2..");
for (int i = 0; i < workLoad; i++) {
Thread.sleep(200);
updateProgress(i, workLoad);
updateMessage(i + " elements done");
}
updateMessage("Task #2 done!");
return null;
}
};
}
}

How can I set the value of a text with "%" in fxml file from the controller?

I want this part of my code with different languge so I am using bundles. I am trying to set the value of text in fxml file with "%" sign to have the value in the bundle.properties file.
I have the following code in the fxml file using Scenebuilder:
<?xml version="1.0" encoding="UTF-8"?>
<?import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox fx:id="iconBox" alignment="CENTER" maxHeight="-Infinity" maxWidth="-
Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="80.0"
prefWidth="80.0" xmlns="http://javafx.com/javafx/18"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.sarf.main.HomeIconsController">
<children>
<FontAwesomeIcon fx:id="iconName" glyphName="STAR" size="26" />
<Label fx:id="iconLabel" text="%anyThing">
<opaqueInsets>
<Insets />
</opaqueInsets>
<VBox.margin>
<Insets top="20.0" />
</VBox.margin>
</Label>
</children>
</VBox>
I am using properties file and trying to set the value of the text from the Controller of the fxml file.
here is the code in the controller:
package com.sarf.main;
import com.sarf.main.models.HomeIcon;
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
//import javafx.scene.layout.VBox;
public class HomeIconsController implements Initializable{
//#FXML
//private VBox iconBox;
#FXML
private FontAwesomeIcon iconName;
#FXML
private Label iconLabel;
#Override
public void initialize(URL url, ResourceBundle rb) {
iconLabel.setText("%grocery");
}
}
the main.java file:
package com.sarf.main;
import java.io.IOException;
import java.util.Locale;
import java.util.ResourceBundle;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.sql.*;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws IOException {
Locale local = new Locale("en_UK");
ResourceBundle bundle =
ResourceBundle.getBundle("com.sarf.main.resources.bundle", local);
Parent rootPane =
FXMLLoader.load(getClass().getResource("fxml/home_icons.fxml"), bundle);
Scene scene = new Scene(rootPane);
primaryStage.setTitle("SARF");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
the resources file is simple. I am just at the beginning of the project. but i faced this porblem. anyway the resources file for now includes one entry:
grocery= Market
when I run the code, the label text is shown like : "%grocery", % sign is interpreted as plain text and the value is not shown as it is in the bundle.properties file.
any help?
Resource resolution is performed by the FXMLLoader when the FXML is parsed. So
<Label fx:id="iconLabel" text="%grocery" />
will result in the text of the label being set to the result of calling getString("grocery") on the resource bundle.
Your code sets the text twice, first in the FXML file, but then again in the initialize() method. The initialize() method is invoked after the text has been set by parsing the FXML file, and of course just sets the text literally to the value provided. So in your code the label's text is initially set to "Market", but then immediately reset to "%grocery".
Remove the line
iconLabel.setText("%grocery");
from the initialize() method and you will see the result you intended.
If you really want to reference the resource bundle in the controller, you can do so as it is passed to the initialize() method. If you remove text="%grocery" from the FXML file, you can do
iconLabel.setText(rb.getString("grocery"));
in the initialize() method (instead of the line you currently have) and that will work too.
Related: see Accessing localisation ResourceBundle inside JavaFX FXML Controller for more information about accessing the resource bundle in the controller.

Using ImageView in JavaFX controller class

I created a javaFX fxml application in NetBeans and want to display an image using a filechooser opened in a handleButtonAction event.
If I drag an ImageView into the panel using the gui builder I see no way to get it's object generated in code.
If I add an Imageview manually to the main class, I do not have the button handler method available, and if I add it to the controller class, I do not have the main panel available to attach the Imageview to. I think I am not understanding how to elements from the ui builder generated into code.
The generated NetBeans projects starts with a hello button that also has no visible object in the source files, so it seems clear that I am missing something about how the ui builder sets the proper xml data to have those elements available to the controller, but there doesn't appear to me to be any way add these to the controller from the ui builder. Is it just that the UI builder is unreliable?
Any help would be appreciated.
The main application class looks like:
package javafxapplication2;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class JavaFXApplication2 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);
}
}
And the Controller:
package javafxapplication2;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
//import javafx.scene.image.Image;
//import javafx.scene.image.ImageView;
//import javafx.stage.FileChooser;
//import javax.imageio.ImageIO;
//import java.io.File;
//import java.io.IOException;
public class FXMLDocumentController implements Initializable {
// private ImageView imgview = new ImageView();
// private FileChooser filechooser = new FileChooser();
#FXML
private void handleButtonAction(ActionEvent event) {
//commented out because it displays nothing
// try {
// File infile = filechooser.showOpenDialog(null);
// Image img = SwingFXUtils.toFXImage(ImageIO.read(infile), null);
// imgview.setImage(img);
// } catch (IOException ex) {
// Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
// }
System.out.println("button clicked");
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
And the XML:
<?import javafx.scene.image.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="355.0" prefWidth="411.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication2.FXMLDocumentController">
<children>
<Button fx:id="button" layoutX="14.0" layoutY="312.0" onAction="#handleButtonAction" text="open file" />
<ImageView fitHeight="150.0" fitWidth="200.0" layoutX="84.0" layoutY="73.0" pickOnBounds="true" preserveRatio="true" />
<Button layoutX="212.0" layoutY="310.0" mnemonicParsing="false" text="Button" />
</children>
</AnchorPane>
You aren't using the ImageView that you have created in the FXML, inside your controller.
You should assign the ImageView a fx:id and then inject it in the controller. This way the same ImageView will be used while setting the Image in the ImageView.
In FXML:
<ImageView fx:id="imgview" fitHeight="150.0" fitWidth="200.0"
layoutX="84.0" layoutY="73.0" pickOnBounds="true" preserveRatio="true" />
In Controller:
public class FXMLDocumentController implements Initializable {
#FXML
private ImageView imgview;
...
}
MCVE
FXML
<?import javafx.scene.control.Button?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="355.0" prefWidth="411.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="FXMLDocumentController">
<children>
<Button fx:id="button" layoutX="14.0" layoutY="312.0" onAction="#handleButtonAction" text="open file" />
<ImageView fx:id="imageView" fitHeight="150.0" fitWidth="200.0" layoutX="84.0" layoutY="73.0" pickOnBounds="true" preserveRatio="true" />
<Button layoutX="212.0" layoutY="310.0" mnemonicParsing="false" text="Button" />
</children>
</AnchorPane>
Controller
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.FileChooser;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
public class FXMLDocumentController implements Initializable {
#FXML
private ImageView imageView;
private FileChooser filechooser = new FileChooser();
#FXML
private void handleButtonAction(ActionEvent event) {
try {
File infile = filechooser.showOpenDialog(null);
Image img = SwingFXUtils.toFXImage(ImageIO.read(infile), null);
imageView.setImage(img);
} catch (IOException ex) {
Logger.getLogger(TestController.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Main
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main 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);
}
}

Why doesn't my Spinner update its bound property the first time it is initialized?

I have a Spinner in controller:
#FXML
private Spinner<Integer> spnMySpinner;
and a SimpleIntegerPropertyin controller:
private static final SimpleIntegerProperty myValue =
new SimpleIntegerProperty(3); //load a default value
I have bound them together in controller's initialize method:
spnMySpinner.getValueFactory().valueProperty().bindBidirectional(myValueProperty().asObject());
But the bindings work correctly only after second time the controller initializes. Here's how I can reproduce it:
I open the stage with the associated controller, it loads the default value, specified in the myValue property correctly (a number 3).
I click the increment button on the spinner to make it a 4. It changes the value in the spinner's value property, but the bound property myValue is left intact with the number 3.
I close the stage/window.
I reopen it, the spinner has again a value of 3.
I increment it again. Boom now the binding works and I have a "4" both inside the spinner and the bound property.
Entire minimalistic, but launchable/reproducible code:
Main.java:
package spinnerpoc;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage stage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
MainWindow.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:id="myRoot" id="AnchorPane" prefHeight="231.0" prefWidth="337.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.60" fx:controller="spinnerpoc.MainWindowController">
<children>
<Button fx:id="btnOpenSpinnerWindow" layoutX="102.0" layoutY="103.0" mnemonicParsing="false" text="Open SpinnerWindow" onAction="#onOpenSpinnerWindow"/>
</children>
</AnchorPane>
MainWindowController.java:
package spinnerpoc;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class MainWindowController implements Initializable {
#FXML
private Button btnOpenSpinnerWindow;
#FXML
private AnchorPane myRoot;
#Override
public void initialize(URL url, ResourceBundle rb) {
}
#FXML
private void onOpenSpinnerWindow(ActionEvent event) throws IOException{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("SpinnerWindow.fxml"));
Parent root = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.initOwner(myRoot.getScene().getWindow());
stage.initModality(Modality.WINDOW_MODAL);
stage.setTitle("SpinnerWindow");
stage.setScene(new Scene(root));
stage.show();
}
}
SpinnerWindow.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.control.Spinner?>
<?import javafx.scene.control.SpinnerValueFactory.DoubleSpinnerValueFactory?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<ScrollPane xmlns:fx="http://javafx.com/fxml/1" fitToWidth="true" prefHeight="200.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.60" fx:controller="spinnerpoc.SpinnerWindowController">
<content>
<VBox maxWidth="1.7976931348623157E308">
<children>
<Spinner fx:id="spnMySpinner" editable="true" prefWidth="50.0" max="10" min="1" />
</children>
</VBox>
</content>
</ScrollPane>
SpinnerWindowController.java:
package spinnerpoc;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Spinner;
public class SpinnerWindowController implements Initializable {
private static final SimpleIntegerProperty myValue = new SimpleIntegerProperty(3);
public static SimpleIntegerProperty myValueProperty() {
return myValue;
}
public static Integer getMyValue() {
return myValue.getValue();
}
public static void setMyValue(int value) {
myValue.set(value);
}
#FXML
private Spinner<Integer> spnMySpinner;
#Override
public void initialize(URL url, ResourceBundle rb) {
spnMySpinner.getValueFactory().valueProperty().bindBidirectional(myValueProperty().asObject());
}
}
(Code also available at a BitBucket repo.)
What am I missing?
You are running into the "premature garbage collection" problem. See a description of this here. You will likely find that it's not always every other time you show the spinner that it fails, but is just sporadic, and that the behavior will vary from one machine to another. If you limit the memory available to the JVM, you might find that it never works.
When you call IntegerProperty.asObject(), it
Creates an ObjectProperty that bidirectionally bound to this IntegerProperty.
Now note that a bidirectional binding has this feature to prevent accidental memory leaks:
JavaFX bidirectional binding implementation use weak listeners. This means bidirectional binding does not prevent properties from being garbage collected.
So the bidirectional binding you explicitly create does not prevent the thing it is bound to (the ObjectProperty<Integer> created by asObject()) from being garbage collected. Since you keep no references to it, it is eligible for garbage collections as soon as you exit the initialize() method in the SpinnerWindow Controller. Obviously, once the value to which your spinner value is bidirectionally bound is garbage collected, the binding will not work any more.
Just for demonstration purposes, you can see this by putting in a hook to force garbage collection. E.g. do
<ScrollPane onMouseClicked="#gc" xmlns:fx="http://javafx.com/fxml/1" ...>
in SpinnerWindow.fxml and
#FXML
private void gc() {
System.out.println("Invoking GC");
System.gc();
}
in SpinnerWindowController. If you do this, then clicking in the scroll pane will force garbage collection, and changing the spinner value will not update the property.
To fix this, retain a reference to the property you get from asObject():
public class SpinnerWindowController implements Initializable {
private static final SimpleIntegerProperty myValue = new SimpleIntegerProperty(3);
public static SimpleIntegerProperty myValueProperty() {
return myValue;
}
public static Integer getMyValue() {
return myValue.getValue();
}
public static void setMyValue(int value) {
myValue.set(value);
}
#FXML
private Spinner<Integer> spnMySpinner;
private ObjectProperty<Integer> spinnerValue = myValueProperty().asObject();
#Override
public void initialize(URL url, ResourceBundle rb) {
spnMySpinner.getValueFactory().valueProperty().bindBidirectional(spinnerValue);
}
}

Calling Fxml file using Start Method which extends Application Class

I want to make a new FXML file which has few Controls like Label. But when I run the application Some times the from is not Showing and Sometime when form is Showing label are not Showing.
I have written the following code:
DashBoard.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="603.0" prefWidth="1063.0" styleClass="mainFxmlClass" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.DashBoard.DashBoardController">
<stylesheets>
<URL value="#dashboard.css" />
</stylesheets>
<children>
<Label fx:id="welcome" layoutX="403.0" layoutY="52.0" text="Label" />
</children>
</AnchorPane>
DashBoardController.java :
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
/**
* FXML Controller class
*
* #author DELL
*/
public class DashBoardController implements Initializable {
/**
* Initializes the controller class.
*/
#FXML
private Label welcome;
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
DashRun.java :
package com.DashBoard;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class DashRun extends Application{
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("DashBoard.fxml"));
Scene scene = new Scene(root);
Label a = new Label();
stage.setTitle("Dash Board");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Resources