5

I am try to restrict the textfield for decimal numbers, I already found the solution for integer number validation here, but the problem is that I am not able to convert the following code for decimal numbers, something like 324.23, 4.3, 4, 2, 10.43. (only 1 decimal point allow).

 vendorList_textField_remaining.textProperty().addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
            if (!newValue.matches("\\d*")) {
                vendorList_textField_remaining.setText(newValue.replaceAll("[^\\d||.]", ""));
            }
        }
    });

I am also looking for alternative solutions. Thanks.

Community
  • 1
  • 1
Faraz Sultan
  • 203
  • 2
  • 13
  • i thnik you need a "look behind" if you want to replace second "." – JohnnyAW Nov 08 '16 at 11:26
  • Why not use a spinner? – Matthew Wright Nov 08 '16 at 11:37
  • i dont know how to use it? – Faraz Sultan Nov 08 '16 at 11:44
  • hmm, just tested and it looks like you can't do it with a look behind, because a look-behind-pattern must have constant length. You could remove all "." except for the last one with a look-ahead, but it's probably the opposite of what you want to achieve... I'm afraid you can't do it with a regex, in that case just loop over the string and remove it manually – JohnnyAW Nov 08 '16 at 11:52
  • 1
    What is the scenario? Please provide a testcase. Also, try `.replaceAll("^(\\d*\\.)|\\D", "$1")`. – Wiktor Stribiżew Nov 08 '16 at 11:54
  • 1
    @WiktorStribiżew hmm, maybe `.replaceAll("^(\\d*\\.\\d*)\\.", "$1")` would do it better... – JohnnyAW Nov 08 '16 at 12:04
  • 1
    Alternative solutions: [DoubleTextField from scenebuider](https://github.com/atrumbo/scenebuilder/blob/master/src/main/java/com/oracle/javafx/scenebuilder/kit/util/control/paintpicker/DoubleTextField.java) – Andrey M Nov 08 '16 at 13:15
  • wiktor stribizew answer works properly. I also try johnnyAW regex but not work as i required. thanks everyone, special thanks to wiktor Stribizew. – Faraz Sultan Nov 08 '16 at 13:35
  • Create your own field validator. You should use regex to test the field for correctness. Once all fields have been validated you can activate the button to process those fields. Also don't forget to use hint text, so that the users know the format of the data that goes into the field. Try this regex: ^[\\d]+(\\.)\\d{1}. It should work for numbers with only one decimal digit. – SedJ601 Nov 08 '16 at 14:26

5 Answers5

7

I have met the same situation. I think I have found the a solution to this question. The regex has to been replaced by a new one and a little changes by setText. For now it works well. The code follows:

vendorList_textField_remaining.textProperty().addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
            if (!newValue.matches("\\d*(\\.\\d*)?")) {
                vendorList_textField_remaining.setText(oldValue);
            }
        }
    });
Xu Li
  • 81
  • 1
  • 4
2

Thanks for help. I have solved my problem with solution (1).

vendorList_textField_remaining.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        if(!newValue.matches("\\d*(\\.\\d*)?")) {
            vendorList_textField_remaining.setText(oldValue);
        }
    }
});
mfaisalhyder
  • 2,250
  • 3
  • 28
  • 38
1

There are some excellent field validation components in the jidefx-oss project, including one for decimal numbers.

David Gilbert
  • 4,427
  • 14
  • 22
1

I tried this approach: (1) On the Textfield - set an EventHandler (2) Call a utility method in the handler to decide if the Key is valid

Setting the handler:

txtField_Rate.setOnKeyTyped(new EventHandler<KeyEvent>() 
{
    @Override
    public void handle(KeyEvent ke) 
    {
        String character = ke.getCharacter();
        String text = txtField_Rate.getText();

         if ( !LM_Utility.isValid_forDouble(text, character, 99.99) )
             ke.consume(); 
    }
});

Requires 2 utility functions:- (1) isValidForDouble

public static boolean isValid_forDouble( String oldText, String newChar, double limit )
{
    boolean valid = false;
    String newText = oldText + newChar;
    int maxDecimals = getDecimals(limit);
    int decimals = 0;

    if ( newChar.matches("[0-9]") )
    {
        decimals = getDecimals(newText);
        if ( Double.valueOf(newText) <= limit )
            if ( decimals <= maxDecimals )
                valid = true;     
    }

    if ( newChar.equals(".") )
    {
        if ( !oldText.contains(".") )
                valid = true;
    }                

    return valid;
} 

and (2) getDecimals()

private static int getDecimals(String value)
{
    int integerPlaces = 0;
    int decimalPlaces = 0;

    if (value.contains("."))
    {
        integerPlaces = value.indexOf('.');
        decimalPlaces = value.length() - integerPlaces - 1;
    }

    return decimalPlaces;
}
gbear
  • 91
  • 4
0

I know that this is old question, but I had same issue and found better solution. I created simple decimal field based on this answer.

It handles decimal with negative values. You can put and remove dot or - even when you already have some numbers entered, so this is very used friendly.

It also compiles pattern only once to ensure better performance(when using text.matches("regex") pattern is compiled every time when someone types character).

When you declare such class, you can use it in a fxml files like it was standard JavaFX component.

public class DecimalField extends TextField {

private static Pattern decimalPattern = Pattern.compile("[-]?[0-9]*(\\.[0-9]*)?");

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

@Override
public void replaceSelection(String text) {
    if (validate(Integer.MAX_VALUE, text)) {
        super.replaceSelection(text);
    }
}

private boolean validate(int start, String text) {
    String currentText = isNull(getText()) ? "" : getText();
    if(start == 0) { //to handle "-1.1" or ".1" cases
        return decimalPattern.matcher(text + currentText).matches();  
    } else {
        return decimalPattern.matcher(currentText + text).matches();
    }
}

}

It also works for integer when you change pattern to: "[-][0-9]"

P. Jowko
  • 111
  • 6