I am trying to create an Integer
Spinner
, but instead, a Double
one is created instead.
Test.class
package com.neonorb.test;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Test extends Application{
@Override
public void start(Stage stage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Demo.fxml"));
Parent root = fxmlLoader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
DemoController.class
package com.neonorb.test;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Spinner;
import java.net.URL;
import java.util.ResourceBundle;
public class DemoController implements Initializable{
@FXML
private Spinner<Integer> spinner;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
System.out.println(spinner.getValue());
}
}
Demo.fxml
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.Spinner?>
<?import java.lang.Integer?>
<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="com.neonorb.test.DemoController">
<Spinner fx:id="spinner" min="1" initialValue="1" amountToStepBy="1">
<max>
<Integer fx:constant="MAX_VALUE"/>
</max>
</Spinner>
</BorderPane>
When I execute it it outputs 1.0
which is how I know it is making a Double
spinner.
I guess what is going on is that FXMLLoader
is choosing the wrong constructor for Spinner
. How do I choose the Integer
one?
It is also possible to assign the controller class directly from the FXML file. In order to do that, you should first open your FXML file and add the following code on the first line of the file right after declarations. Example: Since my controller is inside the package name “view”, my fx: controller = “view.
FXML is an XML-based user interface markup language created by Oracle Corporation for defining the user interface of a JavaFX application. FXML presents an alternative to designing user interfaces using procedural code, and allows for abstracting program design from program logic.
A small update for the FXML file...
Include
<?import javafx.scene.control.SpinnerValueFactory.IntegerSpinnerValueFactory?>
then
<Spinner fx:id="spinner" BorderPane.alignment="CENTER" editable="true" >
<valueFactory>
<SpinnerValueFactory.IntegerSpinnerValueFactory min="0" max="10" initialValue="5" amountToStepBy="1"/>
</valueFactory>
</Spinner>
You need to set a value factory to the spinner. Otherwise you will be faced with the type coercion. If you don't be able to set it there, you can define Integer values that will called by static valueOf().
The JavaFX Introduction to FXML notes about Type Coercion:
Type Coercion
FXML uses "type coercion" to convert property values to the appropriate type as needed. Type coercion is required because the only data types supported by XML are elements, text, and attributes (whose values are also text). However, Java supports a number of different data types including built-in primitive value types as well as extensible reference types.
The FXML loader uses the coerce() method of BeanAdapter to perform any required type conversions. This method is capable of performing basic primitive type conversions such as String to boolean or int to double, and will also convert String to Class or String to Enum. Additional conversions can be implemented by defining a static valueOf() method on the target type.
There already exists a IntegerSpinnerValueFactory. Because it is a nested class of SpinnerValueFactory you have to use it with a dot in the tag-name.
There are three constructors available, you can set min/max and min/max/initialValue and min/max/initialValue/amountToStepBy. This is done by setting it as an attribute.
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.util.* ?>
<?import javafx.scene.*?>
<?import javafx.scene.control.* ?>
<?import javafx.scene.layout.* ?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" fx:controller="demoapp.DemoController">
<center>
<Spinner fx:id="spinner" BorderPane.alignment="CENTER" >
<valueFactory>
<SpinnerValueFactory.IntegerSpinnerValueFactory min="0" max="10"/>
</valueFactory>
</Spinner>
</center>
</BorderPane>
You be also able to define two variables and use them as a static valueOf(). As described in the above quote with the static valueOf() method. So your FXMLLoader does not have to guess which type you probably mean. It calls the constructor with int values.
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.util.* ?>
<?import javafx.scene.*?>
<?import javafx.scene.control.* ?>
<?import javafx.scene.layout.* ?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="demoapp.DemoController" xmlns="http://javafx.com/javafx/8.0_40" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" >
<center>
<fx:define>
<Integer fx:id="min" fx:value="0"/>
<Integer fx:id="max" fx:value="10"/>
</fx:define>
<Spinner fx:id="spinner" BorderPane.alignment="CENTER" min="$min" max="$max">
</Spinner>
</center>
</BorderPane>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With