I am new to Netbeans, JavaFX and Scene Builder. I use latest versions, meaning 8.x. I have a requirement, capture from and to years. Years are 4 digits long and should be numeric.
I found a solution and tested it as a standalone demo. So I created the following FXML and a JAVA to create a JAR which I can import in Scene Builder.
<?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 id="AnchorPane" prefHeight="30.0" prefWidth="150.0" type="AnchorPane" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="numbertextfield.NumberTextField">
<children>
<TextField layoutX="14.0" layoutY="14.0" prefHeight="30.0" prefWidth="150.0" promptText="Enter only numbers " AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</fx:root>
the Controller code is
package numbertextfield;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
/**
*
* @author Hornigold Arthur
*/
public class NumberTextField extends TextField {
private final IntegerProperty maxLength = new SimpleIntegerProperty(this, "maxLength", -1);
private final StringProperty restrict = new SimpleStringProperty(this, "restrict");
@FXML
private TextField numberTextField;
public void NumberTextFieldController() {
// TODO
System.out.println(" Inside NumberTextField Controller");
numberTextField.textProperty().addListener(new ChangeListener<String>() {
private boolean ignore;
@Override
public void changed(ObservableValue<? extends String> observableValue, String s, String s1) {
if (ignore || s1 == null) {
return;
}
if (maxLength.get() > -1 && s1.length() > maxLength.get()) {
ignore = true;
numberTextField.setText(s1.substring(0, maxLength.get()));
ignore = false;
}
if (restrict.get() != null && !restrict.get().equals("") && !s1.matches(restrict.get() + "*")) {
ignore = true;
numberTextField.setText(s);
ignore = false;
}
}
});
//
FXMLLoader fxmlLoader = new FXMLLoader(
getClass().getResource("/NumberTextField.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
//
}
/**
* * The max length property. * * @return The max le
* @return ngth
* property.
*/
public IntegerProperty maxLengthProperty() {
return maxLength;
}
/**
* * Gets the max length of the text field. * * @return The
* max length.
* @return
*/
public int getMaxLength() {
return maxLength.get();
}
/**
* * Sets the max length of the text field. * * @param
* maxLength The max length.
* @param maxLength
*/
public void setMaxLength(int maxLength) {
this.maxLength.set(maxLength);
}
/**
* * The restrict property. * * @return The restrict
* property.
* @return
*/
public StringProperty restrictProperty() {
return restrict;
}
/**
* * Gets a regular expression character class which restricts the user
* input. * * @return The regular expression. * @see
* #getRestrict()
* @return
*/
public String getRestrict() {
return restrict.get();
}
/**
* * Sets a regular expression character class which restricts the user
* input. * E.g. [0-9] only allows numeric values. *
*
*
* @param restrict The regular expression.
*/
public void setRestrict(String restrict) {
this.restrict.set(restrict);
}
}
I imported the jar file in Scene Builder as a custom class and built a FXML for a stand alone module.
<?xml version="1.0" encoding="UTF-8"?>
<?import numbertextfield.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<children>
<NumberTextField fx:id="testNumber" layoutX="226.0" layoutY="125.0" maxLength="4" restrict=""[0-9]"" />
</children>
</AnchorPane>
Following Java code is supposed to load this FXML (Which it does correctly and displays the NumberTextField. But it allows non numeric characters of any length.
package anothertest;
import java.io.IOException;
import javafx.application.Application;
import static javafx.application.ConditionalFeature.FXML;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import numbertextfield.NumberTextField;
/**
*
* @author Hornigold Arthur
*/
public class AnotherTest extends Application {
@FXML
NumberTextField testNumber = new NumberTextField();
@Override
public void start(Stage mainStage) throws Exception {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(AnotherTest.class.getResource("AnotherTest.fxml"));
AnchorPane rootLayout = (AnchorPane) loader.load();
testNumber.setMaxLength(4);
testNumber.setRestrict("[0-9");
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
mainStage.setScene(scene);
mainStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
But the following code Works PERFECTLY which I took from Internet samples.
package testnumberinput;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;
/**
*
* @author Hornigold Arthur
*/
public class TestNumberInput extends Application {
@Override
public void start(Stage primaryStage) {
RestrictiveTextField textInput = new RestrictiveTextField();
textInput.setMaxLength(4);
textInput.setRestrict("[0-9]");
Label label1 = new Label("Enter a number : ");
textInput.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
HBox hBox = new HBox();
hBox.getChildren().addAll(label1, textInput);
StackPane root = new StackPane();
root.getChildren().add(hBox);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("This is a test ..... !");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
/**
* * A text field, which restricts the user's input.
* <p>
* * The restriction can either be a maximal number of characters which the
* user is allowed to input * or a regular expression class, which contains
* allowed characters. * </p>
*
* <p/>
* * <b>Sample, which restricts the input to maximal 10 numeric characters</b>:
*
* <pre>
* * {@code
* * RestrictiveTextField textField = new RestrictiveTextField();
* * textField.setMaxLength(10);
* * textField.setRestrict("[0-9]");
* * }
* * </pre> * * @author Christian Schudt
*/
class RestrictiveTextField extends TextField {
private IntegerProperty maxLength = new SimpleIntegerProperty(this, "maxLength", -1);
private StringProperty restrict = new SimpleStringProperty(this, "restrict");
public RestrictiveTextField() {
textProperty().addListener(new ChangeListener<String>() {
private boolean ignore;
@Override
public void changed(ObservableValue<? extends String> observableValue, String s, String s1) {
if (ignore || s1 == null) {
return;
}
if (maxLength.get() > -1 && s1.length() > maxLength.get()) {
ignore = true;
setText(s1.substring(0, maxLength.get()));
ignore = false;
}
if (restrict.get() != null && !restrict.get().equals("") && !s1.matches(restrict.get() + "*")) {
ignore = true;
setText(s);
ignore = false;
}
}
});
}
/**
* * The max length property. * * @return The max length
* property.
*/
public IntegerProperty maxLengthProperty() {
return maxLength;
}
/**
* * Gets the max length of the text field. * * @return The
* max length.
*/
public int getMaxLength() {
return maxLength.get();
}
/**
* * Sets the max length of the text field. * * @param
* maxLength The max length.
*/
public void setMaxLength(int maxLength) {
this.maxLength.set(maxLength);
}
/**
* * The restrict property.
* * @return The restrict property.
*/
public StringProperty restrictProperty() {
return restrict;
}
/**
* * Gets a regular expression character class which restricts the user
* input. * * @return The regular expression. * @see
* #getRestrict()
*/
public String getRestrict() {
return restrict.get();
}
/**
* * Sets a regular expression character class which restricts the user
* input. * E.g. [0-9] only allows numeric values. *
*
*
* @param restrict The regular expression.
*/
public void setRestrict(String restrict) {
this.restrict.set(restrict);
}
}
Can someone tell me where am I making the mistake ? Thanks a lot.
I MODIFIED THE WHOLE THING AND PUT THEM IN A SINGLE NETBEANS PROJECT FOR CONVENIENCE, TO SEE WHETHER IT WORKS. TELL ME WHETHER THE FOLLOWING PIECES ARE CORRECT. IT STILL DOES NOT WORK. THE FIELD "periodFrom" ALLOWS ME TO TYPE EVERYTHING.
This is fxml-1. (EditedNumber.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 fx:id="numberField" promptText="Enter Number" type="TextField" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" />
This is the controller for fxml-1. (EditedNumber.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 InputNumber;
import java.io.IOException;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.TextField;
/**
*
* @author Hornigold Arthur
*/
public class EditedNumber extends TextField{
/**
*
* @author Hornigold Arthur
*/
private final IntegerProperty maxLength = new SimpleIntegerProperty(this, "maxLength", -1);
private final StringProperty restrict = new SimpleStringProperty(this, "restrict");
@FXML
private TextField numberField;
public void EditedNumber() {
// TODO
System.out.println(" Inside NumberTextField Controller");
numberField = new TextField();
numberField.textProperty().addListener(new ChangeListener<String>() {
private boolean ignore;
@Override
public void changed(ObservableValue<? extends String> observableValue, String s, String s1) {
if (ignore || s1 == null) {
return;
}
if (maxLength.get() > -1 && s1.length() > maxLength.get()) {
ignore = true;
numberField.setText(s1.substring(0, maxLength.get()));
ignore = false;
}
if (restrict.get() != null && !restrict.get().equals("") && !s1.matches(restrict.get() + "*")) {
ignore = true;
numberField.setText(s);
ignore = false;
}
}
});
//
FXMLLoader fxmlLoader = new FXMLLoader(
getClass().getResource("Editor.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
//
/**
* * The max length property. * * @return The max le
*
* @return
*/
public IntegerProperty maxLengthProperty() {
return maxLength;
}
/**
* * Gets the max length of the text field. * * @return The
* max length.
*
* @return
*/
public int getMaxLength() {
return maxLength.get();
}
/**
* * Sets the max length of the text field. * * @param
* maxLength The max length.
*
* @param maxLength
*/
public void setMaxLength(int maxLength) {
this.maxLength.set(maxLength);
}
/**
* * The restrict property. * * @return The restrict
* property.
*
* @return
*/
public StringProperty restrictProperty() {
return restrict;
}
/**
* * Gets a regular expression character class which restricts the user
* input. * * @return The regular expression. * @see
* #getRestrict()
*
* @return
*/
public String getRestrict() {
return restrict.get();
}
/**
* * Sets a regular expression character class which restricts the user
* input. * E.g. [0-9] only allows numeric values. *
*
*
* @param restrict The regular expression.
*/
public void setRestrict(String restrict) {
this.restrict.set(restrict);
}
}
MY ASSUMPTION IS THAT -TOGETHER THEY SHOULD WORK IN A TEAM FOR A NEW UI TYPE.
This is the fxml-2. It uses the EditedNumber UI type. (mainFXML.fxml)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import InputNumber.EditedNumber?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40">
<children>
<Label layoutX="128.0" layoutY="104.0" text="Period From : " textAlignment="RIGHT">
<font>
<Font name="Bookman Old Style" size="18.0" />
</font>
</Label>
<EditedNumber fx:id="periodFrom" layoutX="255.0" layoutY="98.0" style="-fx-background-color: lightblue; -fx-border-color: red; -fx-border-width: 2;">
<font>
<Font name="Bookman Old Style" size="18.0" />
</font>
</EditedNumber>
</children>
</AnchorPane>
This is the controller (or the main program) (InputNumber.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 InputNumber;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
/**
*
* @author Hornigold Arthur
*/
public class InputNumber extends Application {
@FXML
EditedNumber periodFrom;
@Override
public void start(Stage mainStage) {
periodFrom = new EditedNumber();
periodFrom.setMaxLength(4);
periodFrom.setRestrict("[0-9]");
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(InputNumber.class.getResource("mainFXML.fxml"));
AnchorPane rootLayout = (AnchorPane) loader.load();
Scene scene = new Scene(rootLayout);
mainStage.setScene(scene);
mainStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
There are no compilation errors. If this works fine, then I can move the EDITED NUMBER Class to Scene Builder and see whether it works correctly.
Thanks in advance for your guidance.