Como obter o mesmo valor que o usuário está vendo a partir de um JFormattedTextField?
-
18-09-2019 - |
Pergunta
Eu estou usando um NumberFormatter
e JFormattedTextField
, mas o .getValue()
não retorna o mesmo valor que o usuário está vendo.
Eu acho que o input-string é analisado usando NumberFormats parse-método, e tenho a Numberformat de NumberFormat.getNumberInstance();
com a localidade real. Então eu não acho que facilmente pode estendê-lo e escrever a minha própria análise do método?
No exemplo , se o usuário digitar 1234.487
o getValue()
retornará:
1234.487
mas o usuário será exibido 1,234.49
Outro exemplo , usando NumberFormat.getCurrencyInstance();
. O 1234.487
tipos de usuário ea getValue()
voltará 1234.487
mas o usuário será exibido $1,234.49
Em vez disso , eu quero um ParseException ser gerado se o Formatter não pode formatar o valor sem arredondamento. A mesma coisa se o 4.35b6
tipos de usuários, por padrão, o formatador irá exibir 4.35
eo valor será 4.35
, mas eu quero uma ParseException, porque o usuário digitou um inválido valor.
Aqui está o código que eu tentei com:
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());
}
});
Como obter o mesmo valor que o usuário está vendo?
Solução
Você deve se estender NumberFormatter
em vez de NumberFormat
e override stringToValue
para que ele verifica que quando a corda é analisado você recebe de volta o 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"));
Esta formatador vai rejeitar o novo texto se os valores antes e depois de arredondamento não coincidem.
Nota: este compara os valores , e não as cordas. Vai tolerar alterações como a remoção de caracteres de agrupamento ("$1,000"
=> "$1000"
) e zeros à direita ("$1.20"
=> "$1.2"
). Basicamente, se o NumberFormat
retorna o mesmo valor, então é aceitável. Mas quaisquer restrições impostas pelo NumberFormat
ainda se aplicam, por exemplo, Você não deve remover o símbolo de moeda ou inserção principais espaços etc.
Outras dicas
Tente isto:
txt.setText(ftf.getFormatter().valueToString(ftf.getValue()));
Você também terá que lidar com a java.text.ParseException
que o método valueToString
joga.
Editar: O formatador pode ser configurado para não permitir entradas inválidas por completo, o que pode ajudar:
((DefaultFormatter)ftf.getFormatter()).setAllowsInvalid( false );