Issue
i'm using TextFomater to make my TextField as a dynamic monetary textfield, using the following code:
public class MoneyTextFieldOperator implements UnaryOperator<TextFormatter.Change>
{
final char seperatorChar = '.';
final Pattern p;
int length;
public MoneyTextFieldOperator(int length) {
this.length=length;
this.p = Pattern.compile("[0-9. ]*");
}
@Override
public TextFormatter.Change apply(final TextFormatter.Change c) {
if (c.isContentChange() && c.getControlNewText().length() > length) {
return null;
}
else {
if (!c.isContentChange()) {
return c;
}
final String newText = c.getControlNewText();
if (newText.isEmpty()) {
return c;
}
if (!this.p.matcher(newText).matches()) {
return null;
}
final int suffixCount = c.getControlText().length() - c.getRangeEnd();
int digits = suffixCount - suffixCount / 4;
final StringBuilder sb = new StringBuilder();
if (digits % 3 == 0 && digits > 0 && suffixCount % 4 != 0) {
sb.append('.');
}
for (int i = c.getRangeStart() + c.getText().length() - 1; i >= 0; --i) {
final char letter = newText.charAt(i);
if (Character.isDigit(letter)) {
sb.append(letter);
if (++digits % 3 == 0) {
System.out.println("digits : "+digits);
sb.append('.');
}
}
}
if (digits % 3 == 0) {
sb.deleteCharAt(sb.length() - 1);
}
sb.reverse();
final int length = sb.length();
c.setRange(0, c.getRangeEnd());
c.setText(sb.toString());
c.setCaretPosition(length);
c.setAnchor(length);
return c;
}}
And calling it as follow :
montantTextField.setTextFormatter(new TextFormatter(new MoneyTextFieldOperator(10)));
the issue is that it's valable just for integer numbers, and i want make it now valable for decimal numbers, so when the user type 254648,32 it converts it to 254.648,32
Solution
here is a proposed solution using numberformat :
public class MoneyTextFieldOperator implements UnaryOperator<TextFormatter.Change> {
Pattern p;
int length;
public MoneyTextFieldOperator(int length) {
this.length = length;
this.p = Pattern.compile("[0-9. ,]*");
}
@Override
public TextFormatter.Change apply(TextFormatter.Change c) {
Pattern acceptedKeywords = Pattern.compile("[0-9 . ,]*");
int wholeNumberLength = 9;
int decimalPartLength = 2;
String newText = c.getControlNewText();
String wholeNumber;
String decimalPart;
if (newText.contains(",")) {
wholeNumber = newText.substring(0, newText.indexOf(","));
decimalPart = newText.substring(newText.indexOf(",") + 1, newText.length());
} else {
wholeNumber = newText;
decimalPart = "";
}
Matcher matcher = acceptedKeywords.matcher(newText);
boolean isMatchingWithAcceptedKeywords = matcher.matches();
String letter = c.getText();
if (newText.isEmpty()) {
return c;
} else if (!c.isContentChange()) {
return c;
} else if (countChar(c.getControlNewText(), ',') > 1) {
return null;
} else if (!isMatchingWithAcceptedKeywords) {
return null;
} else if (wholeNumber.replace(".", "").length() > wholeNumberLength || decimalPart.length() > decimalPartLength) {
return null;
} else if (c.getControlNewText().charAt(0)==',') {
return null;
}
else {
c.setRange(0, c.getControlText().length());
if (newText.contains(",")) {
c.setText(NumbersTools.getMonetaryFormat(Integer.parseInt(wholeNumber.replace(".", ""))) + "," + decimalPart);
} else {
c.setText(NumbersTools.getMonetaryFormat(Integer.parseInt(wholeNumber.replace(".", ""))));
}
c.setCaretPosition(c.getText().length());
c.setAnchor(c.getText().length());
return c;
}
}
public int countChar(String string, char charactere) {
int x = 0;
for (int i = 0; i <= string.length() - 1; ++i) {
if (string.charAt(i) == charactere) {
++x;
}
}
return x;
}
and you use it as follow :
textField.setTextFormatter(new TextFormatter<Object>(new MoneyTextFieldOperator(10)));
Answered By - Youssef Idraiss
Answer Checked By - Senaida (JavaFixing Volunteer)