Numeric TextField for Integers in JavaFX 8 with TextFormatter and/or UnaryOperator
The converter is different to the filter: the converter specifies how to convert the text to a value, and the filter filters changes the user may make. It sounds like here you want both, but you want the filter to more accurately filter the changes that are allowed.
I usually find it easiest to check the new value of the text if the change were accepted. You want to optionally have a -
, followed by 1-9
with any number of digits after it. It's important to allow an empty string, else the user won't be able to delete everything.
So you probably need something like
UnaryOperator<Change> integerFilter = change -> {
String newText = change.getControlNewText();
if (newText.matches("-?([1-9][0-9]*)?")) {
return change;
}
return null;
};
myNumericField.setTextFormatter(
new TextFormatter<Integer>(new IntegerStringConverter(), 0, integerFilter));
You can even add more functionality to the filter to let it process -
in a smarter way, e.g.
UnaryOperator<Change> integerFilter = change -> {
String newText = change.getControlNewText();
// if proposed change results in a valid value, return change as-is:
if (newText.matches("-?([1-9][0-9]*)?")) {
return change;
} else if ("-".equals(change.getText()) ) {
// if user types or pastes a "-" in middle of current text,
// toggle sign of value:
if (change.getControlText().startsWith("-")) {
// if we currently start with a "-", remove first character:
change.setText("");
change.setRange(0, 1);
// since we're deleting a character instead of adding one,
// the caret position needs to move back one, instead of
// moving forward one, so we modify the proposed change to
// move the caret two places earlier than the proposed change:
change.setCaretPosition(change.getCaretPosition()-2);
change.setAnchor(change.getAnchor()-2);
} else {
// otherwise just insert at the beginning of the text:
change.setRange(0, 0);
}
return change ;
}
// invalid change, veto it by returning null:
return null;
};
This will let the user press -
at any point and it will toggle the sign of the integer.
SSCCE:
import java.util.function.UnaryOperator;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TextFormatter.Change;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;
import javafx.util.converter.IntegerStringConverter;
public class IntegerFieldExample extends Application {
@Override
public void start(Stage primaryStage) {
TextField integerField = new TextField();
UnaryOperator<Change> integerFilter = change -> {
String newText = change.getControlNewText();
if (newText.matches("-?([1-9][0-9]*)?")) {
return change;
} else if ("-".equals(change.getText()) ) {
if (change.getControlText().startsWith("-")) {
change.setText("");
change.setRange(0, 1);
change.setCaretPosition(change.getCaretPosition()-2);
change.setAnchor(change.getAnchor()-2);
return change ;
} else {
change.setRange(0, 0);
return change ;
}
}
return null;
};
// modified version of standard converter that evaluates an empty string
// as zero instead of null:
StringConverter<Integer> converter = new IntegerStringConverter() {
@Override
public Integer fromString(String s) {
if (s.isEmpty()) return 0 ;
return super.fromString(s);
}
};
TextFormatter<Integer> textFormatter =
new TextFormatter<Integer>(converter, 0, integerFilter);
integerField.setTextFormatter(textFormatter);
// demo listener:
textFormatter.valueProperty().addListener((obs, oldValue, newValue) -> System.out.println(newValue));
VBox root = new VBox(5, integerField, new Button("Click Me"));
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 300, 120);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Tutorial
A comprehensive tutorial guide on using a TextFormatter
:
- Pragmatic coding JavaFX TextFormatter tutorial.
What is the recommended way to make a numeric TextField in JavaFX?
Very old thread, but this seems neater and strips out non-numeric characters if pasted.
// force the field to be numeric only
textField.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue,
String newValue) {
if (!newValue.matches("\\d*")) {
textField.setText(newValue.replaceAll("[^\\d]", ""));
}
}
});
Text Field that accepts only numbers
Problem solved. All I had to do is replacing setTextFormatter
with delegateSetTextFormatter
and here is the new code:
UnaryOperator<TextFormatter.Change> integerFilter = change -> {
String newText = change.getControlNewText();
if (newText.matches("-?([1-9][0-9]*)?")) {
return change;
}
return null;
};
MFXTextField.delegateSetTextFormatter(
new TextFormatter<Integer>(new IntegerStringConverter(), null, integerFilter));
Java 8 U40 TextFormatter (JavaFX) to restrict user input only for decimal number
Please see this example:
DecimalFormat format = new DecimalFormat( "#.0" );
TextField field = new TextField();
field.setTextFormatter( new TextFormatter<>(c ->
{
if ( c.getControlNewText().isEmpty() )
{
return c;
}
ParsePosition parsePosition = new ParsePosition( 0 );
Object object = format.parse( c.getControlNewText(), parsePosition );
if ( object == null || parsePosition.getIndex() < c.getControlNewText().length() )
{
return null;
}
else
{
return c;
}
}));
Here I used the TextFormatter(UnaryOperator filter) constructor which takes a filter only as a parameter.
To understand the if-statement refer to DecimalFormat parse(String text, ParsePosition pos).
JavaFX TextField listener gives java.lang.IllegalArgumentException: The start must be = the end
Using the same idea as the duplicate. You need to define a regular expression that matches binary numbers.
I am using "\\b[01]+\\b"
to define binary numbers and ""
to define an empty TextField
.
MCVE
import java.util.function.UnaryOperator;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.TextFormatter.Change;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class TestingGroundsTwo extends Application
{
public static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage stage)
{
UnaryOperator<Change> binaryFilter = change -> {
String newText = change.getControlNewText();
if (newText.matches("\\b[01]+\\b") || newText.matches("")) {
return change;
}
return null;
};
TextField textField = new TextField();
textField.setTextFormatter(new TextFormatter<>(binaryFilter));
stage.setTitle("Hello World!");
Scene scene = new Scene(new StackPane(textField), 750, 125);
scene.setFill(Color.GHOSTWHITE);
stage.setScene(scene);
stage.show();
}
}
Limit TextField to a specific range of number JavaFX?
You can use regex
to allow your specific numbers' range(1-19) and add that validation on TextField's TextFormatter's filter
.
Regex => ([1-9]|1[0-9])
[1-9]
Either TextField allows you to enter 1 to 9 numbers1[0-9]
Or TextField allows you to enter 10 to 19 numbers
Regex Circut
TextField Validation Demo
public class TextFieldValidationDemo extends Application {
private static final String REGEX_VALID_INTEGER = "([1-9]|1[0-9])";
@Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
root.setCenter(getRootPane());
primaryStage.setScene(new Scene(root, 200, 200));
primaryStage.show();
}
private BorderPane getRootPane() {
BorderPane root = new BorderPane();
root.setCenter(getTextField());
return root;
}
private TextField getTextField() {
TextField field = new TextField();
field.setTextFormatter(new TextFormatter<>(this::filter));
return field;
}
private TextFormatter.Change filter(TextFormatter.Change change) {
if (!change.getControlNewText().matches(REGEX_VALID_INTEGER)) {
change.setText("");
}
return change;
}
}
Related Topics
Oracle Jdbc Intermittent Connection Issue
What Does Super.Paintcomponent(G) Do
Configure Datasource Programmatically in Spring Boot
Check Is a Point (X,Y) Is Between Two Points Drawn on a Straight Line
Is Autoboxing Possible for the Classes I Create
Generic Support for Iso 8601 Format in Java 6
How Does Java Order Items in a Hashmap or a Hashtable
Is It Necessary to Close Each Nested Outputstream and Writer Separately
Looking for Java Spell Checker Library
Java Web Service Client Basic Authentication
Java: Rationale of the Cloneable Interface
Using Bufferedreader.Readline() in a While Loop Properly
How to Attach Multiple Files to an Email Using Javamail
Having a Column Name as Input Parameter of a Preparedstatement