Search code examples
regexjavafxtextfieldzipcode

JavaFX - TextField with regex for zipcode


for my programm I want to use a TextField where the user can enter a zipcode (German ones). For that I tried what you can see below. If the user enters more than 5 digits every additional digit shall be deleted immediately. Of course letters are not allowed.

When I use this pattern ^[0-9]{0,5}$ on https://regex101.com/ it does what I intended to, but when I try this in JavaFX it doesn't work. But I couldn't find a solution yet.

Can anyone tell me what I did wrong?

Edit: For people, who didn't work with JavaFX yet: When the user enters just one character, the method check(String text) is called. So the result should also be true, when there are 1 to 5 digits. But not more ;-)


public class NumberTextField extends TextField{

    ErrorLabel label;

    NumberTextField(String text, ErrorLabel label){
        setText(text);
        setFont(Font.font("Calibri", 17));
        setMinHeight(35);
        setMinWidth(200);
        setMaxWidth(200);
        this.label = label;
    }

    NumberTextField(){}

    @Override
    public void replaceText(int start, int end, String text){
        if(check(text)) {
            super.replaceText(start, end, text);
        }
    }

    @Override
    public void replaceSelection(String text){
        if(check(text)){
            super.replaceSelection(text);
        }
    }

    private boolean check(String text){
        if(text.matches("^[0-9]{0,5}$")){
            label.setText("Success");
            label.setBlack();
            return true;
        } else{
            return false;
        }
    }


Solution

  • You don't need to extend TextField to do this. In fact I recommend using a TextFormatter, since this is simpler to implement:
    It does not require you to overwrite multiple method. You simply need to decide based on the data about the desired input, if you want to allow the change or not.

    final Pattern pattern = Pattern.compile("\\d{0,5}");
    TextFormatter<?> formatter = new TextFormatter<>(change -> {
        if (pattern.matcher(change.getControlNewText()).matches()) {
            // todo: remove error message/markup
            return change; // allow this change to happen
        } else {
            // todo: add error message/markup
            return null; // prevent change
        }
    });
    TextField textField = new TextField();
    textField.setTextFormatter(formatter);