JAVAFx TextField Validation Decimal value

2020-02-29 06:17发布

问题:

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.

回答1:

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);
            }
        }
    });


回答2:

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



回答3:

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;
}


回答4:

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);
        }
    }
});


回答5:

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]"