JFormattedTextField со строгим числовым форматом разбора

Поскольку кто-то пометил мой другой вопрос (анализ числового формата недостаточно строгий) как дубликат по ошибке и не удалил дубликат ярлыка, хотя я указал, что он другой, я снова опубликую вопрос вместе со своим решением. Может быть, это полезно для кого-то. Вот так:

У меня есть JFormattedTextField с NumberFormat с Locale.US. Таким образом, десятичный разделитель — это точка, а группирующий разделитель — запятая.

Теперь я набираю в этом текстовом поле строку «1,23» и перемещаю фокус на другой компонент. Я бы ожидал, что строка исчезнет (как это происходит, когда я набираю «a» вместо «1,23»), потому что это явно недопустимое представление числа при использовании Locale.US. Но вместо этого текст в текстовом поле меняется на «123».

Это связано с тем, что используемый NumberFormat не является строгим при разборе и просто игнорирует запятую.

Вопрос. Как в этом случае указать NumberFormat, чтобы он вызывал ParseException, чтобы текстовое поле было пустым после перемещения фокуса на другой компонент?

Тестовый код:

    JDialog dialog = new JDialog();
    JPanel panel = new JPanel(new BorderLayout());
    dialog.getContentPane().add(panel);

    NumberFormat nf = NumberFormat.getInstance(Locale.US);
    JFormattedTextField textField = new JFormattedTextField(nf);
    textField.setText("1,23");
    panel.add(textField, BorderLayout.CENTER);
    panel.add(new JButton("focus"), BorderLayout.EAST);

    dialog.pack();
    dialog.setVisible(true);

Переместите фокус с текстового поля на кнопку, и текст изменится на «123».


person General Martok    schedule 19.11.2015    source источник


Ответы (1)


Вот мое решение:

Сначала я создаю собственный DecimalFormat со строгим разбором. Допускаются только цифры и не более одной десятичной точки.

    public class StrictDecimalFormat extends DecimalFormat {

        private static final Pattern NUMBER_PATTERN = Pattern.compile("^\\d*[.]?\\d*$");

        public Number parse(String text, ParsePosition pos) {
            Matcher matcher = NUMBER_PATTERN.matcher(text);
            if (matcher.matches()) {
                return super.parse(text, pos);
            }
            return null;
        }
    }

Теперь я использую этот десятичный формат для своего JFormattedTextField. Поскольку сама локаль не может быть установлена ​​в десятичном формате, я должен создать соответствующий DecimalFormatSymbols и установить его.

    DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(Locale.US);
    DecimalFormat strictFormat = new StrictDecimalFormat();
    strictFormat.setDecimalFormatSymbols(decimalFormatSymbols);

    JDialog dialog = new JDialog();
    JPanel panel = new JPanel(new BorderLayout());
    dialog.getContentPane().add(panel);

    JFormattedTextField textField = new JFormattedTextField(strictFormat);
    textField.setText("1,23");
    panel.add(textField, BorderLayout.CENTER);
    panel.add(new JButton("focus"), BorderLayout.EAST);

    dialog.pack();
    dialog.setVisible(true);
person General Martok    schedule 19.11.2015