JavaFX TextField validation for integer input and also allow either K or k(for Thousand) or M or m(for Million) in last

后端 未结 3 1789
鱼传尺愫
鱼传尺愫 2021-01-21 11:40

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

3条回答
  •  北恋
    北恋 (楼主)
    2021-01-21 12:11

    I created the following class to filter input on TextField, which also uses the TextFormatter introduced in JavaFX 8.

    public class TextFieldValidator {
    
        private static final String CURRENCY_SYMBOL   = DecimalFormatSymbols.getInstance().getCurrencySymbol();
        private static final char   DECIMAL_SEPARATOR = DecimalFormatSymbols.getInstance().getDecimalSeparator();
    
        private final Pattern       INPUT_PATTERN;
    
        public TextFieldValidator(@NamedArg("modus") ValidationModus modus, @NamedArg("maxCountOf") int maxCountOf) {
            this(modus.createPattern(maxCountOf));
        }
    
        public TextFieldValidator(@NamedArg("regex") String regex){
            this(Pattern.compile(regex));
        }
    
        public TextFieldValidator(Pattern pattern){ 
            INPUT_PATTERN = pattern;
        }
    
        public static TextFieldValidator maxFractionDigits(int maxCountOf) {
            return new TextFieldValidator(maxFractionPattern(maxCountOf));
        }
    
        public static TextFieldValidator maxIntegers(int maxCountOf) {
            return new TextFieldValidator(maxIntegerPattern(maxCountOf));
        }
    
        public static TextFieldValidator integersOnly() {
            return new TextFieldValidator(integersOnlyPattern());
        }
    
        public TextFormatter getFormatter() {
            return new TextFormatter<>(this::validateChange);
        }
    
        private Change validateChange(Change c) {
            if (validate(c.getControlNewText())) {
                return c;
            }
            return null;
        }
    
        public boolean validate(String input) {
            return INPUT_PATTERN.matcher(input).matches();
        }
    
        private static Pattern maxFractionPattern(int maxCountOf) {
            return Pattern.compile("\\d*(\\" + DECIMAL_SEPARATOR + "\\d{0," + maxCountOf+ "})?");
        }
    
        private static Pattern maxCurrencyFractionPattern(int maxCountOf) {
            return Pattern.compile("^\\" + CURRENCY_SYMBOL + "?\\s?\\d*(\\" + DECIMAL_SEPARATOR + "\\d{0," + maxCountOf+ "})?\\s?\\" +
                    CURRENCY_SYMBOL + "?");
        }
    
        private static Pattern maxIntegerPattern(int maxCountOf) {
            return Pattern.compile("\\d{0," + maxCountOf+ "}");
        }
    
        private static Pattern integersOnlyPattern() {
            return Pattern.compile("\\d*");
        }
    
        public enum ValidationModus {
    
            MAX_CURRENCY_FRACTION_DIGITS {
                @Override
                public Pattern createPattern(int maxCountOf) {
                    return maxCurrencyFractionPattern(maxCountOf);
                }
            },
    
            MAX_FRACTION_DIGITS {
                @Override
                public Pattern createPattern(int maxCountOf) {
                    return maxFractionPattern(maxCountOf);
                }
            },
            MAX_INTEGERS {
                @Override
                public Pattern createPattern(int maxCountOf) {
                    return maxIntegerPattern(maxCountOf);
                }
            },
    
            INTEGERS_ONLY {
                @Override
                public Pattern createPattern(int maxCountOf) {
                    return integersOnlyPattern();
                }
            };
    
            public abstract Pattern createPattern(int maxCountOf);
        }
    }
    
    
    

    You can use it like this:

    textField.setTextFormatter(new TextFieldValidator(ValidationModus.MAX_INTEGERS, 4).getFormatter());
    

    or you can instantiate it in a fxml file, and apply it to a customTextField with the according properties.

    app.fxml:

    
        
    
    
    
    

    CustomTextField:

    public class CustomTextField {
    
    private TextField textField;
    
    public CustomTextField(@NamedArg("validator") TextFieldValidator validator) {
            this();
            textField.setTextFormatter(validator.getFormatter());
        }
    }
    

    For your usecase you could call the TextFieldValidor constructor with the appropriate regex pattern and add the filter of James-D's answer to validateChange(Change c)

    提交回复
    热议问题