Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Control keyboard input into javafx TextField

Tags:

java

javafx

I want to control the input into a Javafx TextField so that I can allow only Numeric input, and so that if the max characters are exceeded, then no change will be made to the textbox.

edit: Based on a recommendation in the comments, I used the method suggested by the JavaFX project lead. It works great to stop letters from being entered. I just need it to also filter special characters. I tried changing the filter to (text.matchs("[0-9]") but that did not allow backspace to be entered.

edit2: Figured out a filter on special chars and length. Here is my final code. Thanks for the input fellas.

Here is the TextField class i have created:

import javafx.scene.control.TextField;

public class AttributeTextField extends TextField{

    public AttributeTextField() {
        setMinWidth(25);
        setMaxWidth(25);
    }

    public void replaceText(int start, int end, String text) {
        String oldValue = getText();
        if (!text.matches("[a-z]") && !text.matches("[\\\\!\"#$%&()*+,./:;<=>?@\\[\\]^_{|}~]+")) {
            super.replaceText(start, end, text);
        }
        if (getText().length() > 2 ) {
            setText(oldValue);
        }
    }

    public void replaceSelection(String text) {
        String oldValue = getText();
        if (!text.matches("[a-z]") && !text.matches("[\\\\!\"#$%&()*+,./:;<=>?@\\[\\]^_{|}~]+")) {
            super.replaceSelection(text);
        }
        if (getText().length() > 2 ) {
            setText(oldValue);
        }
    }
}

Note: I have read What is the recommended way to make a numeric TextField in JavaFX? this post, and this solution does not work for me. It only gets fired after the number has been entered. Meaning someone could type alphabetic text into the box, and it would allow it until they moved focus away from the textfield. Also, they can enter numbers larger than allowed, but validation happens not on each keypress, but instead after focus shift ('changed' event).

like image 450
Damienknight Avatar asked Oct 03 '13 19:10

Damienknight


2 Answers

Final solution. Disallows alphabetic and special characters and enforces character limit.

import javafx.scene.control.TextField;

public class AttributeTextField extends TextField{

    public AttributeTextField() {
        setMinWidth(25);
        setMaxWidth(25);
    }

    public void replaceText(int start, int end, String text) {
        String oldValue = getText();
        if (!text.matches("[A-Za-z]") && !text.matches("[\\\\!\"#$%&()*+,./:;<=>?@\\[\\]^_{|}~]+")) {
            super.replaceText(start, end, text);
        }
        if (getText().length() > 2 ) {
            setText(oldValue);
        }
    }

    public void replaceSelection(String text) {
        String oldValue = getText();
        if (!text.matches("[A-Za-z]") && !text.matches("[\\\\!\"#$%&()*+,./:;<=>?@\\[\\]^_{|}~]+")) {
            super.replaceSelection(text);
        }
        if (getText().length() > 2 ) {
            setText(oldValue);
        }
    }
}
like image 79
Damienknight Avatar answered Nov 10 '22 00:11

Damienknight


Here is my aproach, two event filters, could be one, in my case i used them in diferent situations, thats why there are two.

Here is the maxValueFilter (in spanglish xD), this one is a class:

public class FilterMaxValue implements EventHandler<KeyEvent> {

        private int maxVal;

        public FilterMaxValue (int i) {
            this.maxVal= i;
        }

        public void handle(KeyEvent arg0) {

            TextField tx = (TextField) arg0.getSource();
            String chara = arg0.getCharacter();
            if (tx.getText().equals(""))
                return;

            Double valor;
            if (chara.equals(".")) {
                valor = Double.parseDouble(tx.getText() + chara + "0");
            } else {
                try {
                    valor = Double.parseDouble(tx.getText() + chara);
                } catch (NumberFormatException e) {
                    //The other filter will prevent this from hapening
                    return;
                }
            }
            if (valor > maxVal) {
                arg0.consume();
            }

        }
    }

And the other event filter (filters the chars), this one is a method:

public static EventHandler<KeyEvent> numFilter() {

        EventHandler<KeyEvent> aux = new EventHandler<KeyEvent>() {
            public void handle(KeyEvent keyEvent) {
                if (!"0123456789".contains(keyEvent.getCharacter())) {
                    keyEvent.consume();

                }
            }
        };
        return aux;
    }

the use in your case would be:

field.addEventFilter(KeyEvent.KEY_TYPED,
                numFilter());
field.addEventFilter(KeyEvent.KEY_TYPED, new FiltroValorMaximo(
                99));
like image 28
Magcus Avatar answered Nov 09 '22 23:11

Magcus