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

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

    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.

提交回复
热议问题