0

I'm trying to create a field which accepts doubles only. I want the value to be commited without the user having to click on enter. So I am setting a listener to the changes that are happening and setting the value each time.

Here is some of my code:

// Change the behaviour of the converter to avoid empty strings and values outside the defined bounds
    valueFactory.setConverter(new StringConverter<Double>() {
        private final DecimalFormat format = new DecimalFormat("#.##");
        @Override
        public String toString(Double value) {
             if (value == null) {
                 return format.format(0);
             }

             return value.toString();
        }

        @Override
        public Double fromString(String string) {
             try {
                 if (string == null || string.trim().length() < 0 || string.trim().length() > MAX_LENGTH) {
                     return null;
                 } else {
                    Double newVal = format.parse(string).doubleValue();
                    return (newVal >= min && max >= newVal) ? newVal : null;
                 }
             } catch (Exception ex) {
                 return 0.00;
             }
        }
    });

    // Define a formatter on the text entered into the field
    TextFormatter<Object> textFormatter = new TextFormatter<>(c -> {
        if (c.getText().matches("[^0-9.]+") && !c.getText().trim().isEmpty()) {
            return null;
        }
        if(c.getControlNewText().length() <= MAX_LENGTH) {
            try {
                Double newVal = Double.valueOf(c.getControlNewText());

                return (newVal >= min && max >= newVal) ? c : null;
            } catch (Exception ex) {
                if(c.getControlNewText().isEmpty()) {
                    c.setText("0.00");
                } else if(c.getControlNewText().length() == 1) {
                     c.setText("0.00");
                } else {
                    c.setText("");
                }

                return c;
            }
        } else {
            c.setText("");
            return c;
        }
    });

    getEditor().setTextFormatter(textFormatter);

    getEditor().textProperty().addListener(new ChangeListener<String>() {
        public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
            if(!newValue.trim().isEmpty()) {
                try {
                    setValue(Double.parseDouble(newValue), amountToStepBy);
                } catch(Exception e) {
                    setValue(min, amountToStepBy);
                    getEditor().setText(min.toString());
                }
            }
        }
    });

I want the user to only be able to add double numbers in the format #.## only. The problem is this fails when I enter a number like 0.00000001 and I get an exception:

java.lang.IllegalArgumentException: The start must be <= the end
at javafx.scene.control.TextInputControl.getText(TextInputControl.java:446)
at javafx.scene.control.TextInputControl.updateContent(TextInputControl.java:564)
at javafx.scene.control.TextInputControl.replaceText(TextInputControl.java:548)
at com.sun.javafx.scene.control.skin.TextFieldSkin.replaceText(TextFieldSkin.java:576)

Also the text field gets edited with the value 1.0E-8.

Suemayah Eldursi
  • 969
  • 4
  • 14
  • 36
  • It appears you are changing the value of the text field, while somebody is typing it in? – matt Sep 15 '17 at 11:57
  • Can you create a [MCVE]? Does the stack trace reference any of the lines of code that you posted? – James_D Sep 15 '17 at 12:10
  • Probably not the cause of the problem, but note that your regex is wrong. `.` will match any character, so the first `if` clause can never be true. You want `"[^0-9\\.]+"` for the regex. (`\.`matches a literal `"."`, and of course you need to escape the `\\` in a literal string.) – James_D Sep 15 '17 at 12:46

0 Answers0