Issue
I have modified NumberFormatter
to have like a currency instance (with prefix).
When I write the first number, this application have add the prefix to the number
JFormattedTextField Empty
but when I do that, the caret position change before the first number like this
enter image description here
How can I fix this by only modifying method formato()
– that returns a NumberFormatter
– to the constructor of JFormattedTextField
?
textFieldMonto = new javax.swing.JFormattedTextField(formato());
This is the method:
private NumberFormatter formato() {
DecimalFormat myFormatter = new DecimalFormat("'Gs. '###,##0;'Gs. '###,##0");
NumberFormatter numberFormatter = new NumberFormatter(myFormatter) {
// this change caret to the end in every focus gained
@Override
public void install(JFormattedTextField pField) {
super.install(pField);
pField.setCaretPosition(pField.getDocument().getLength());
}
// allow empty text on JFormattedTextField and dont allow negative numbers
@Override
public String valueToString(Object value) throws ParseException {
String result = super.valueToString(value);
if(super.valueToString(value).startsWith("-"))
result = result.replaceFirst("-", ""); // this block every negative number
if(value==null)
return "";
return result;
}
// allow empty text on JFormattedTextField and dont allow negative numbers
@Override
public Object stringToValue(String text) throws ParseException {
if (text.length() == 0 || text.equals("Gs. ")) // if is empty or only have the prefix, return null
return null;
text.replaceFirst("-", ""); // this block every negative number
if(!text.startsWith("Gs. ")) //if is empty, add the prefix "Gs. " to the number
text = "Gs. " + text;
return super.stringToValue(text);
}
};
numberFormatter.setAllowsInvalid(false); //this is the key!!
numberFormatter.setMaximum(new BigDecimal("999999999999"));// maximum number to put
numberFormatter.setCommitsOnValidEdit(true);// commit value on each keystroke instead of focus lost
return numberFormatter;
}
Solution
I don't think this comment, in the code in your question, is true:
// this change caret to the end in every focus gained
Method install
is not called every time the JFormattedTextField
gains focus. According to my tests, it is called only when a JFormattedTextField
object is created.
According to the javadoc:
Subclasses will typically only need to override this if they wish to install additional listeners on the
JFormattedTextField
.
Hence I suggest adding a DocumentListener to the JFormattedTextField
's document, in method install
.
Note that there are other DocumentListener
s that are set up by the Swing infrastructure and since there is no guarantee regarding the order of execution when there is more than one DocumentListener
, the implementation, in the below code, uses invokeLater to ensure that the listener that I added is run last.
Here is my rewrite of your formato
method.
The only thing I changed was method install
.
private NumberFormatter formato() {
DecimalFormat myFormatter = new DecimalFormat("'Gs. '###,##0;'Gs. '###,##0");
NumberFormatter numberFormatter = new NumberFormatter(myFormatter) {
// this change caret to the end in every focus gained
@Override
public void install(JFormattedTextField pField) {
super.install(pField);
pField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
EventQueue.invokeLater(() -> pField.setCaretPosition(pField.getDocument().getLength()));
}
@Override
public void removeUpdate(DocumentEvent e) {
EventQueue.invokeLater(() -> pField.setCaretPosition(pField.getDocument().getLength()));
}
@Override
public void changedUpdate(DocumentEvent e) {
// Do nothing.
}
});
}
// allow empty text on JFormattedTextField and don't allow negative numbers
@Override
public String valueToString(Object value) throws ParseException {
String result = super.valueToString(value);
if(super.valueToString(value).startsWith("-"))
result = result.replaceFirst("-", ""); // this block every negative number
if(value==null)
return "";
return result;
}
// allow empty text on JFormattedTextField and don't allow negative numbers
@Override
public Object stringToValue(String text) throws ParseException {
if (text.length() == 0 || text.equals("Gs. ")) // if is empty or only have the prefix, return null
return null;
text.replaceFirst("-", ""); // this block every negative number
if(!text.startsWith("Gs. ")) //if is empty, add the prefix "Gs. " to the number
text = "Gs. " + text;
return super.stringToValue(text);
}
};
numberFormatter.setAllowsInvalid(false); //this is the key!!
numberFormatter.setMaximum(new BigDecimal("999999999999"));// maximum number to put
numberFormatter.setCommitsOnValidEdit(true);// commit value on each keystroke instead of focus lost
return numberFormatter;
}
Answered By - Abra
Answer Checked By - Pedro (JavaFixing Volunteer)