DecimalFormat точка и запятая как decimalSeparator

однажды я написал этот код для форматирования ввода JFormattedTextField

DecimalFormat decimalFormat = new DecimalFormat("#0.00");
NumberFormatter nf = new NumberFormatter(decimalFormat);
nf.setValueClass(Double.class);
nf.setAllowsInvalid(true);
nf.setOverwriteMode(false);
tfPreisIntern = new JFormattedTextField(nf);

через некоторое время я понял проблему, которая возникает, если пользователь вводит, например, 4,50 вместо 4.50, тогда значение устанавливается на 4.00 вместо 4.50 или 4,50. Я думаю, что это проблема моего DecimalFormat. теперь мой вопрос: возможно ли использовать запятую и точку в качестве возможного десятичного разделителя? обходные пути тоже в порядке

мой метод преобразования значения из JFormattedTextField в BigDecimal:

public static BigDecimal getBigDecimal(Object value) {
    BigDecimal ret = null;
    if (value != null) {
        if (value instanceof BigDecimal) {
            ret = (BigDecimal) value;
        } else if (value instanceof String) {
            ret = new BigDecimal((String) value);
        } else if (value instanceof BigInteger) {
            ret = new BigDecimal((BigInteger) value);
        } else if (value instanceof Number) {
            ret = new BigDecimal(((Number) value).doubleValue());
        } else {
            throw new ClassCastException("Not possible to coerce [" + value + "] from class " + value.getClass()
                    + " into a BigDecimal.");
        }
    }
    return ret;
}

проблема с запятой, которую я вижу здесь, заключается в том, что конструктор BigDecimal(string) допускает только десятичную точку, а не запятую

РЕДАКТИРОВАТЬ:

теперь пробую с MaskFormatter вот так:

    MaskFormatter mask = new MaskFormatter("*#.##");
    mask.setPlaceholderCharacter(' ');
    mask.setCommitsOnValidEdit(false);

но я не могу вводить такие значения, как 2.50. это работает, только если я использую маску типа #.##. но мне нужно иметь возможность значений с 1 и 2 цифрами перед точкой


person XtremeBaumer    schedule 03.05.2017    source источник
comment
Я предполагаю, что setAllowsInvalid(true) позволит проанализировать и недопустимое значение, но даст вам максимально возможное значение, используя comma, только левая часть будет соответствовать, поэтому он не может получить .50. У меня нет документации (пока), чтобы написать ответ об этом   -  person AxelH    schedule 03.05.2017
comment
Что касается вашего редактирования, у меня была аналогичная проблема не так давно, к счастью для меня, формат был только "123456.789" или "123456,789", поэтому только десятичный разделитель, поэтому я просто заменяю , на ., чтобы соответствовать требованиям BigDecimal, но если есть шанс, что вы получите "123,456.789", вы больше не можете его использовать.   -  person AxelH    schedule 03.05.2017
comment
@AxelH это сработает, но в текстовом поле также всегда должен отображаться опубликованный десятичный формат. я также думал об этом решении, но я не могу заставить его работать, так как мне нужно изменить все на обычные JTextFields, а затем многие методы не работают должным образом   -  person XtremeBaumer    schedule 03.05.2017
comment
Как сказано в комментариях к ответу, вы можете следовать этому руководству по форматированию текстовое поле. Это может помочь вам   -  person AxelH    schedule 03.05.2017


Ответы (1)


Изучив руководство по Oracle, вы обнаружите, что:

  • для форматирования можно изменить символы форматирования, но
  • для парсинга такой вещи нет.

И это имеет большой смысл: вы просто спрашиваете: «Я хочу, чтобы пользователь мог получать все виды противоречивых данных, и код должен волшебным образом превратить это в то, что имел в виду пользователь».

Один из способов улучшить взаимодействие с пользователем: вместо использования форматированного текстового поля; вы можете просто разрешить пользователю вводить строки. А затем вы пишете валидаторы, которые позволяют осуществить это «волшебство».

Другими словами: если вы хотите, чтобы "4,59" и "4,59" были одинаковыми, вам нужно написать код для этого. Это может быть так же просто, как использовать indexOf(), чтобы понять, если "." или "," присутствует во входящей строке (ONCE); а затем попробуйте использовать «форматированный» синтаксический анализ для каждого из случаев, используя разные шаблоны. Если вы выберете этот крутой путь в бездну, начните читать о InputVerifiers здесь Например.

Но, конечно: это может оказаться сложным; потому что, как сказано; вы фактически позволяете пользователю вводить любые данные; и ожидайте догадаться, что он имеет в виду.

Мои личные два цента: поместите много предупреждений/примеров вокруг этого текстового поля; и разрешить ровно один тип ввода на основе локали. И шлепать пользователей по пальцам, когда он это нарушает.

person GhostCat    schedule 03.05.2017
comment
Это немного сложнее, поскольку некоторые местные жители используют . или , в качестве разделителя тысяч. 100,000.00. Но мысль правильная конечно. Чтобы добавить немного больше информации, формат использует . в качестве заполнителя для десятичного разделителя. Таким образом, он будет основан на локальном соответствии с правильным разделителем. - person AxelH; 03.05.2017
comment
мы можем просто предположить, что тысячи никогда не будут введены, и даже если разделителей тысяч быть не должно. если я использую это решение, я думаю, что мне понадобится помощь, чтобы переписать метод, который дает мне BigDecimal из разных классов, так как я думаю, что проверка должна произойти там. проблема с пользователями в том, что некоторые из них английские, а некоторые немецкие и поэтому имеют разные десятичные разделители - person XtremeBaumer; 03.05.2017
comment
@AxelH - это поле цены, поэтому дробь должна содержать только 2 цифры и не более. - person XtremeBaumer; 03.05.2017
comment
@XtremeBaumer В финансах у вас есть валюты с 3 цифрами (всего несколько), но вы также можете иметь цену с 3, 6, 8 десятичными знаками. Так что это не везде верно, к сожалению. Но это будет работать для локальной системы, такой как управление магазином или что-то еще, что не работает с топливом (тоже 3 десятичных знака). - person AxelH; 03.05.2017
comment
я думаю, что могу работать с форматированием маски, но я не могу заставить работать последнюю вещь, которая будет иметь формат ##.## и по-прежнему отображать значения, такие как 2.50. если я использую формат #.##, то я не могу отображать такие значения, как 12.30. если вы можете дать мне совет, чтобы сделать эту работу, я буду очень благодарен - person XtremeBaumer; 03.05.2017
comment
Вы получили мой голос за это; но, к сожалению, это слишком далеко от моих нынешних знаний; и это означало бы, что я должен начать экспериментировать сам, чтобы найти решение (которое может на самом деле существовать или не существовать) ... и я боюсь, что мое время слишком ограничено, чтобы пойти на это сегодня. - person GhostCat; 03.05.2017