I want to add validation in javafx TextField such that user should only be able to insert integer values ([0-9] and Dot ). Also user should be able to insert either B or b(for B
As well as listening to changes in the text property and reverting if they are invalid, you can use a TextFormatter to veto changes to the text. Using this approach will avoid other listeners to the textProperty
seeing the invalid value and then seeing it revert to the previous value: i.e. the textProperty
will always contain something valid.
The TextFormatter
takes a UnaryOperator
which acts as a filter. The filter can return null to veto the change entirely, or can modify properties of the Change
as needed.
Here is a fairly straightforward example, where "k" or "K" is replaced by "000", "m" or "M" by "000000", and other non-digit characters are removed:
import java.util.function.UnaryOperator;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TextFormatter.Change;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TextFieldFilteringExample extends Application {
@Override
public void start(Stage primaryStage) {
TextField textField = new TextField();
textField.textProperty().addListener((obs, oldValue, newValue) -> {
System.out.println("Text change from "+oldValue+" to "+newValue);
});
UnaryOperator filter = change -> {
if (change.isAdded()) {
String addedText = change.getText();
if (addedText.matches("[0-9]*")) {
return change ;
}
// remove illegal characters:
int length = addedText.length();
addedText = addedText.replaceAll("[^0-9kKmM]", "");
// replace "k" and "K" with "000":
addedText = addedText.replaceAll("[kK]", "000");
// replace "m" and "M" with "000000":
addedText = addedText.replaceAll("[mM]", "000000");
change.setText(addedText);
// modify caret position if size of text changed:
int delta = addedText.length() - length ;
change.setCaretPosition(change.getCaretPosition() + delta);
change.setAnchor(change.getAnchor() + delta);
}
return change ;
};
textField.setTextFormatter(new TextFormatter(filter));
StackPane root = new StackPane(textField);
root.setPadding(new Insets(20));
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
You could also modify the text to introduce grouping separators (e.g. 1,000,000), though the logic gets quite tricky there. You can additionally specify a StringConverter
for the text formatter, so that the formatter itself has a value of type BigInteger
which is the result of passing the text through the supplied converter.