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

后端 未结 3 1794
鱼传尺愫
鱼传尺愫 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:01

    You can listen to changes in the text property to check for valid inputs. Personally I prefer the user being able to input any string and not preventing any edits until the user commits the edit.

    The following example is for BigInteger (for simplicity) only and allows any number starting with non-zero and followed either only by digits or by digits that are grouped to 3 digits by seperating them with ,. It adds the CSS class invalid, if the input is not valid and converts it to a string containing only digits if the user presses enter:

    // regex for matching the input and extracting the parts
    private static final Pattern NUMBER_PATTERN = Pattern.compile("([1-9](?:\\d*|\\d{0,2}(?:\\,\\d{3})*))([tbmk]?)", Pattern.CASE_INSENSITIVE);
    
    // map from suffix to exponent for 10
    private static final Map SUFFIX_EXPONENTS;
    
    static {
        Map prefixes = new HashMap<>();
        prefixes.put('k', (byte) 3);
        prefixes.put('m', (byte) 6);
        prefixes.put('b', (byte) 9);
        prefixes.put('t', (byte) 12);
        SUFFIX_EXPONENTS = Collections.unmodifiableMap(prefixes);
    }
    
    private static BigInteger convert(String s) {
        if (s == null) {
            return null;
        }
    
        Matcher m = NUMBER_PATTERN.matcher(s);
    
        if (!m.matches()) {
            return null;
        }
    
        String numberString = m.group(1).replace(",", "");
        String suffix = m.group(2);
    
        BigInteger factor = suffix.isEmpty() ? BigInteger.ONE : BigInteger.TEN.pow(SUFFIX_EXPONENTS.get(Character.toLowerCase(suffix.charAt(0))));
    
        return new BigInteger(numberString).multiply(factor);
    }
    
    @Override
    public void start(Stage primaryStage) throws Exception {
        TextField tf = new TextField();
        tf.getStyleClass().add("invalid");
    
        // property bound to the current number in the TextField or null, if invalid
        ObjectProperty numberProperty = new SimpleObjectProperty<>();
    
        // Binding reevaluated on every change of the text property.
        // A listener could be used instead to change the text to the
        // previous value, if the new input is invalid.
        numberProperty.bind(Bindings.createObjectBinding(() -> convert(tf.getText()), tf.textProperty()));
    
        // change styleclass, if the string becomes (in)valid input
        numberProperty.addListener((observable, oldValue, newValue) -> {
            if (oldValue == null) {
                tf.getStyleClass().remove("invalid");
            } else if (newValue == null) {
                tf.getStyleClass().add("invalid");
            }
        });
    
        // handle user pressing enter
        tf.setOnAction(evt -> {
            BigInteger num = numberProperty.get();
            tf.setText(num == null ? null : num.toString());
        });
    
        Pane root = new StackPane(tf);
    
        Scene sc = new Scene(root, 300, 300);
    
        sc.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
    
        primaryStage.setScene(sc);
        primaryStage.show();
    }
    

    In the stylesheet I set the background for invalid textfields to red-tone to give the user visual feedback:

    .text-field.invalid {
        -fx-background-color: #f55;
    }
    

    If you want to prevent users from inputing anything that cannot be made a valid string by apending chars, you could remove numberProperty and everything related to it and add a listener that reverts to the old value instead:

    tf.textProperty().addListener((observable, oldValue, newValue) -> {
        if (isInvalid(newValue)) {
            tf.setText(oldValue);
        }
    });
    

提交回复
热议问题