0

Below Java regular expression operate in a TextField in my program. It will allow to user to input only digits [0-9], press keyboard TAB and ESCAPE. How can I make to allow to press keyboard BACKSPACE and DELETE key?

void restrictNumbersOnly(KeyEvent keyEvent) {
   if (keyEvent.getCharacter().matches("[^\\e\t\r\\d+$]")) {
       /* SOME WARNING MSG */
       keyEvent.consume();
    }
}

keyEvent.getCode() == KeyCode.BACK_SPACE is not working. I've try to do this in this way:

void restrictLettersOnly(KeyEvent keyEvent) {
        if (keyEvent.getCharacter().matches("[^\\e\t\r\\d+$]")) {
            if (keyEvent.getCode() == KeyCode.BACK_SPACE) {
                /* DO NOTHING */
            } else {
                /* SOME WARNING MSG */
                keyEvent.consume();
            }
        }
    }
GoRobotFlame
  • 145
  • 2
  • 9
  • 1
    Why not use `getKeyCode()` and the VK constants (e.g. [VK_BACK_SPACE](https://docs.oracle.com/javase/8/docs/api/java/awt/event/KeyEvent.html#VK_BACK_SPACE))? – GriffeyDog Dec 12 '16 at 19:18
  • Like that: `(keyEvent.getCode() == KeyCode.BACK_SPACE && (keyEvent.getCharacter().matches("[^\\e\t\r\\d+$]"))` ? This won't work. – GoRobotFlame Dec 12 '16 at 19:28
  • Possible duplicate of [How to detect backspace in a keyTypedEvent](http://stackoverflow.com/questions/30679878/how-to-detect-backspace-in-a-keytypedevent) – Aleksandr Erokhin Dec 12 '16 at 19:56
  • 1
    You should not restrict characters this way. You haven’t said whether this is Swing or JavaFX, but both of them have better ways to validate numeric entry. – VGR Dec 12 '16 at 20:05
  • This is JavaFX. – GoRobotFlame Dec 12 '16 at 20:14
  • What are you actually try my to do? As @VGR points out this just looks like the wrong approach. For example, what happens if the user uses the mouse to copy and paste text into the text field? How is your key event going to have any effect on that? – James_D Dec 12 '16 at 20:53

3 Answers3

4

I changed question title to help other with better search.

So, I have solved this problem by doing this:

Allow to input only letters:

   textField.textProperty().addListener((observable, oldValue, newValue) -> {
        if (!newValue.matches("\\sa-zA-Z*")) {
            textField.setText(newValue.replaceAll("[^\\sa-zA-Z]", ""));
        }
    });

Allow to input only numbers:

   textField.textProperty().addListener((observable, oldValue, newValue) -> {
        if (!newValue.matches("\\d*")) {
            textField.setText(newValue.replaceAll("[^\\d]", ""));
        }
    });

These codes will also allow user to press ESCAPEDELETEBACKSPACESPACE... etc...

GoRobotFlame
  • 145
  • 2
  • 9
  • 2
    The correct way to verify integer input is to define a TextFormatter with `new TextFormatter(new NumberStringConverter(NumberFormat.getIntegerInstance()))`, pass it to your TextField’s setTextFormatter method, and make use of the TextFormatter’s [value](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TextFormatter.html#valueProperty) property (by binding to it or by adding a listener to it). Depending on what the number is for, a [Spinner](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/Spinner.html) might be a more appropriate control than a TextField. – VGR Dec 12 '16 at 21:29
2

This is how I did it using TextFormatter:

UnaryOperator<TextFormatter.Change> doubleFilter = change -> {
    String input = change.getText();

    if ((input.matches("[\\d\\.]+")) || change.isDeleted()) {
        return change;
    }
    return null;
};


textField.setTextFormatter(new TextFormatter<String> (doubleFilter));

This will only allow numbers, the period (.) and backspace / delete etc.

Michael Sims
  • 2,360
  • 1
  • 16
  • 29
0

You cannot use getCharacter in the KEY_PRESSED event. From the javadoc:

For key pressed and key released events, character is always CHAR_UNDEFINED.

You can instead use getCode and getText or simply use KeyCode's methods:

void restrictNumbersOnly(KeyEvent keyEvent) {
    switch (keyEvent.getCode()) {
        case TAB:
        case BACK_SPACE:
        case DELETE:
            break;
        default:
            if (!keyEvent.getText().matches("\\d")) {
            // if (!keyEvent.getCode().isDigitKey()) {
                keyEvent.consume();
            }
    }
}

void restrictLettersOnly(KeyEvent keyEvent) {
    KeyCode code = keyEvent.getCode();
    switch (code) {
        case TAB:
        case BACK_SPACE:
        case DELETE:
            break;
        default:
            if (!code.isLetterKey()) {
                keyEvent.consume();
            }
    }
}

To restrict the input you need to use one of those methods in a event filter:

textField.addEventFilter(KeyEvent.KEY_PRESSED, this::restrictNumbersOnly);
fabian
  • 80,457
  • 12
  • 86
  • 114