3

Я использую NumberFormatter и JFormattedTextField, но .getValue() не возвращает то же значение, что и пользователь.Как получить то же значение, что пользователь видит из JFormattedTextField?

Я думаю, что входная строка анализируется с использованием метода parse-метода NumberFormats, и я получаю Numberformat от NumberFormat.getNumberInstance(); с фактической локалью. Поэтому я не думаю, что я могу легко расширить его и написать свой собственный метод анализа?

В примере, если пользователь 1234.487 getValue() вернется: 1234.487, но пользователь будет отображаться 1,234.49

Другой пример, используя NumberFormat.getCurrencyInstance();. Типы пользователей 1234.487 и getValue() вернутся 1234.487, но пользователь будет отображаться $1,234.49

Вместо, Я хочу ParseException генерироваться, если Formatter не может форматировать значения без округления. То же самое, если пользователь набирает 4.35b6, по умолчанию форматтер будет отображать 4.35, и значение будет 4.35, но я хочу исключение ParseException, потому что пользователь напечатал недействительным значение.

Вот код, который я попытался с:

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()); 
    } 
}); 

Как получить то же самое значение, что и пользователь видит?

+1

Этот вопрос связан и улучшит решение: http: // stackoverflow.com/questions/1680120/javas-decimalformat-how-to-reject-invalid-input-with-grouped-decimals – Jonas

ответ

6

Вы должны расширить NumberFormatter вместо NumberFormat и переопределить stringToValue так, что она проверяет, когда строка проанализирован, вы возвращаете исходное значение:

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")); 

Этот форматтер отклонит новый текст, если значение s до и после округления не совпадают.

Примечание: это сравнивает значения , а не строки. Он будет терпеть изменения, такие как удаление групповых символов ("$1,000" =>"$1000") и конечные нули ("$1.20" =>"$1.2"). В основном, если NumberFormat возвращает то же значение, то это приемлемо. Но все ограничения, налагаемые NumberFormat, все еще применяются, например. вы не должны удалять символ валюты или вставлять начальные пробелы и т. д.

+0

Будет ли это работать в случае форматирования валюты? – Ash

+0

@Ash, да, я просто попробовал его с 'getCurrencyInstance()'. Он должен работать с любым действительным «NumberFormat». – finnw

+0

С помощью этого решения было легко редактировать текстовое поле, поэтому я пойду с этим. Благодаря! – Jonas

3

Попробуйте это:

txt.setText(ftf.getFormatter().valueToString(ftf.getValue())); 

Вы также должны будете обрабатывать java.text.ParseException, что метод valueToString бросков.

Edit: Форматировщик можно установить, чтобы запретить недействительных записей в целом, которые могут помочь:

((DefaultFormatter)ftf.getFormatter()).setAllowsInvalid(false); 
+0

Это не работает. Затем вам нужно снова проанализировать строку, потому что строка содержит форматирование, например currencysymbol и группировку цифр. И я не думаю, что есть парсер для строк с currencysymbols? – Jonas

+1

Когда я запускаю ваш код (с приведенным выше изменением) и набираю «1234.487», я вижу «1,234.49» в обоих полях. Разве это не то, что вы хотели? – Ash

+0

Нет, мне нужно значение, а не строка, поэтому я могу делать вычисления. Если бы я хотел этого, я мог бы использовать getText(). Я думаю, что если пользователь вводит три цифры фракции, необходимо создать ParseException и форматировать не следует делать округление, это важно. Если мне нравится ваш пример, значение имеет символ группировки между 1 и 2, поэтому мне нужно снова его проанализировать. – Jonas

Смежные вопросы