¿Cómo obtener el mismo valor que el usuario está viendo desde un JFormattedTextField?
-
18-09-2019 - |
Pregunta
Estoy usando un NumberFormatter
y JFormattedTextField
, pero el .getValue()
no devuelve el mismo valor que el usuario está viendo.
Creo que la entrada-serie se analiza usando NumberFormats analizan método, y consigo el Numberformat de NumberFormat.getNumberInstance();
con la configuración regional real. Así que no creo que fácilmente puede extenderlo y escribir mi propio análisis sintáctico-método?
En el ejemplo , si el usuario 1234.487
la getValue()
volverá:
1234.487
pero se mostrará al usuario 1,234.49
Otro ejemplo , utilizando NumberFormat.getCurrencyInstance();
. El 1234.487
tipos de utilización y el getValue()
volverán 1234.487
pero el usuario se mostrarán $1,234.49
En lugar , quiero una ParseException generarse si el formateador no puede formatear el valor sin redondeo. Lo mismo si el usuario escribe 4.35b6
, por defecto el formateador mostrará 4.35
y se 4.35
el valor, pero quiero un ParseException, debido a que el usuario escribió en un no válido valor.
Este es el código que he tratado con:
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMaximumFractionDigits(2);
nf.setMinimumFractionDigits(2);
final JFormattedTextField ftf = new JFormattedTextField(nf);
ftf.setValue(new BigDecimal("1234.50"));
// Print the value from ftf
final JTextField txt = new JTextField(12);
txt.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent e) {
txt.setText(ftf.getValue().toString());
}
});
¿Cómo obtener el mismo valor que el usuario está viendo?
Solución
Se debe extender NumberFormatter
en lugar de NumberFormat
y anular stringToValue
para que verifica que cuando se analiza la cadena obtiene nuevamente el valor original:
class StrictNumberFormatter extends javax.swing.text.NumberFormatter {
@Override
public Object stringToValue(String text) throws ParseException {
Object parsedValue = super.stringToValue(text);
String expectedText = super.valueToString(parsedValue);
if (! super.stringToValue(expectedText).equals(parsedValue)) {
throw new ParseException("Rounding occurred", 0);
}
return parsedValue;
}
public StrictNumberFormatter(NumberFormat nf) {
super(nf);
}
}
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMaximumFractionDigits(2);
nf.setMinimumFractionDigits(2);
JFormattedTextField.AbstractFormatter formatter = new StrictNumberFormatter(nf);
final JFormattedTextField ftf = new JFormattedTextField(formatter);
ftf.setValue(new BigDecimal("1234.50"));
Este formateador rechace el nuevo texto si los valores antes y después de redondeo no coinciden.
Nota: esto se compara los valores , no las cuerdas. Se tolerará cambios como la eliminación de caracteres de agrupación ("$1,000"
=> "$1000"
) y ceros ("$1.20"
=> "$1.2"
). Básicamente, si el NumberFormat
devuelve el mismo valor, entonces es aceptable. Sin embargo, las restricciones impuestas por el NumberFormat
todavía se aplican, por ejemplo, no se debe quitar el símbolo de moneda o insertar espacios iniciales, etc.
Otros consejos
Prueba esto:
txt.setText(ftf.getFormatter().valueToString(ftf.getValue()));
También tendrá que manejar la java.text.ParseException
que el método valueToString
lanza.
Editar El formateador puede ser configurado para no permitir entradas no válidas en total, lo que podría ayudar:
((DefaultFormatter)ftf.getFormatter()).setAllowsInvalid( false );