Use a converter in the text formatter you are using to filter the input:
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.function.UnaryOperator;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
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;
public class DecimalTextField extends Application {
@Override
public void start(Stage primaryStage) {
// decimal formatter for default locale:
DecimalFormat decimalFormat = new DecimalFormat();
decimalFormat.setMinimumFractionDigits(1);
DecimalFormatSymbols symbols = decimalFormat.getDecimalFormatSymbols() ;
char decimalSep = symbols.getDecimalSeparator() ;
UnaryOperator<Change> filter = change -> {
for (char c : change.getText().toCharArray()) {
if ( (! Character.isDigit(c)) && c != decimalSep) {
return null ;
}
}
return change ;
};
StringConverter<Double> converter = new StringConverter<Double>() {
@Override
public String toString(Double object) {
return object == null ? "" : decimalFormat.format(object);
}
@Override
public Double fromString(String string) {
try {
return string.isEmpty() ? 0.0 : decimalFormat.parse(string).doubleValue();
} catch (ParseException e) {
return 0.0 ;
}
}
};
TextFormatter<Double> formatter = new TextFormatter<>(converter, 0.0, filter);
TextField textField = new TextField();
textField.setTextFormatter(formatter);
VBox root = new VBox(10, textField, new TextArea());
root.setAlignment(Pos.CENTER);
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
(Obviously the filter could be improved here to, e.g. avoid multiple decimal separator characters in the input.)