I want to add validation in javafx TextField such that user should only be able to insert integer values ([0-9] and Dot ). Also user should be able to insert either B or b(for Billion) and K or k (for Thousand) and M or m( for Million). Basically it should be an amountfield. Delete and Backspace should also work.
for example :
10k should become 10,000.00 as soon as user hit k and K should not be displayed on amountfield (textfield) Similarly 10M or 10m should convert into 10,000,000.00
adsadi342fn3 or 31233123werwer or dsad342134k should not be allowed to enter in the textfield.
I have used getKeyChar method while validating TextField in case of Swing. But I need same implementation in case of JavaFx where we don't have getKeyChar method.
I have used the following method but the problem with this is it allows user to enter any value. example : sdafewr23rf
private void amountEntered() {
if (amountField != null) {
String value;
char[] charArray = amountField.getText().toCharArray();
if (charArray.length > 0)
switch (charArray[charArray.length - 1]) {
case 't':
case 'T':
value = multiplyValue(amountField.getText(), new BigDecimal(1000000000000.0));
updateAmount(value);
break;
case 'b':
case 'B':
value = multiplyValue(amountField.getText(), new BigDecimal(1000000000.0));
updateAmount(value);
break;
case 'm':
case 'M':
value = multiplyValue(amountField.getText(), new BigDecimal(1000000.0));
updateAmount(value);
break;
case 'k':
case 'K':
value = multiplyValue(amountField.getText(), new BigDecimal(1000.0));
updateAmount(value);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
case ',':
updateAmount(amountField.getText());
break;
default:
break;
}
}
}
private String multiplyValue(String number, BigDecimal multValue) {
//get rid of "," for double parsing
BigDecimal value = new BigDecimal(cleanDouble(number.substring(0, number.length() - 1)));
value = value.multiply(multValue);
return value.toPlainString();
}
As well as listening to changes in the text property and reverting if they are invalid, you can use a
TextFormatter
to veto changes to the text. Using this approach will avoid other listeners to thetextProperty
seeing the invalid value and then seeing it revert to the previous value: i.e. thetextProperty
will always contain something valid.The
TextFormatter
takes aUnaryOperator<TextFormatter.Change>
which acts as a filter. The filter can return null to veto the change entirely, or can modify properties of theChange
as needed.Here is a fairly straightforward example, where "k" or "K" is replaced by "000", "m" or "M" by "000000", and other non-digit characters are removed:
You could also modify the text to introduce grouping separators (e.g. 1,000,000), though the logic gets quite tricky there. You can additionally specify a
StringConverter<BigInteger>
for the text formatter, so that the formatter itself has a value of typeBigInteger
which is the result of passing the text through the supplied converter.I created the following class to filter input on
TextField
, which also uses theTextFormatter
introduced in JavaFX 8.You can use it like this:
or you can instantiate it in a fxml file, and apply it to a customTextField with the according properties.
app.fxml:
CustomTextField:
For your usecase you could call the TextFieldValidor constructor with the appropriate regex pattern and add the filter of James-D's answer to
validateChange(Change c)
You can listen to changes in the
text
property to check for valid inputs. Personally I prefer the user being able to input any string and not preventing any edits until the user commits the edit.The following example is for
BigInteger
(for simplicity) only and allows any number starting with non-zero and followed either only by digits or by digits that are grouped to 3 digits by seperating them with,
. It adds the CSS classinvalid
, if the input is not valid and converts it to a string containing only digits if the user presses enter:In the stylesheet I set the background for invalid textfields to red-tone to give the user visual feedback:
If you want to prevent users from inputing anything that cannot be made a valid string by apending chars, you could remove
numberProperty
and everything related to it and add a listener that reverts to the old value instead: