Как получить то же значение, которое видит пользователь из JFormattedTextField? - PullRequest
3 голосов
/ 05 февраля 2010

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

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

Например , если пользователь вводит 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, поскольку пользователь ввел недопустимое значение . 1033 *

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

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

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

Ответы [ 2 ]

6 голосов
/ 05 февраля 2010

Вы должны расширить 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"));

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

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

3 голосов
/ 05 февраля 2010

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

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

Вам также придется обрабатывать java.text.ParseException, который выбрасывает метод valueToString.

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

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