1

i once have written this code to format the input of 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);

after some time i realized the problem that occurs if the user enters for example 4,50 instead of 4.50 then the value is set to 4.00 instead of 4.50 or 4,50. i think its an problem of my DecimalFormat. now my question is, is it possible to have comma and point as possible decimal separator? workarounds are also okay

my method to convert the value from the JFormattedTextField into 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;
}

the problem with an comma i see here is that the constructor BigDecimal(string) only allows a decimal point and not a comma

EDIT:

now trying with MaskFormatter like this:

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

but i can't enter values like 2.50. this only works if i use a mask like #.##. yet i need to have the possibility of values with 1 and 2 digits before the dot

XtremeBaumer
  • 6,275
  • 3
  • 19
  • 65
  • I guess the `setAllowsInvalid(true)` will permit to parse and invalid value but will give you the closest value possible, using a `comma`, only the left part will match so it can't retrieve the `.50`. I don't have documentation (yet) to write an answer about that – AxelH May 03 '17 at 08:33
  • About your edit, I had a similar problem not so long ago, luckily for me, the format was only `"123456.789"` or `"123456,789"`, so only a decimal separator, so I simply replace `,` with `.` to match the `BigDecimal` requirements, but if there is a chance you get `"123,456.789"`, you can't use that anymore. – AxelH May 03 '17 at 09:10
  • @AxelH this would work, but the textfield should also always show the posted decimal format. i also thought about this solution, but i can't get it to work as i have to change everything to normal JTextFields and then many methods don't work as intended – XtremeBaumer May 03 '17 at 09:22
  • As said in the answer comments, you might want to follow this [guide on formatted textfield](https://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html). This might help you – AxelH May 03 '17 at 09:56

1 Answers1

2

When you check the Oracle tutorial you can find that:

  • for formatting it is possible to alter the formatting symbols, but
  • for parsing there is no such thing.

And that makes a lot of sense: you are simply asking "I want the user to be able all kind of inconsistent data; and code shall magically turn that into what the user meant".

One way to improve the user experience: instead of using a formatted text field; you could simply allow the user to enter strings. And then you write validators that allow for that "magic" to happen.

In other words: if you want that "4,59" and "4.59" should result as the same thing, then you need to write code for that. Which could be as simple as using indexOf() to figure if "." or "," is present in the incoming string (ONCE); and then try to use "formatted" parsing for each of the cases using different patterns. If you decide for that steep route into the abyss, start reading about InputVerifiers here for example.

But of course: that can turn out to be complicated; because as said; you are basically allowing the user to put in whatever data; and expect to guess what he means with that.

My personal two cent: put a lot of warnings/examples around that text field; and allow exactly one locale based kind of input. And slap users fingers when he violates that.

Community
  • 1
  • 1
GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • This is a bit more complication than that since some local use a `.` or `,` as thousand separator. `100,000.00`. But the idea is correct of course. To add a bit more information, the format use `.` as a _placeholder for decimal separator_. So it will be based on the local to match the correct separator – AxelH May 03 '17 at 08:37
  • we can simply assume that thousands will never be entered and even if, there shouldn't be thousand separators. if i use this solution, i think ill need some help to rewrite a method which gives me a BigDecimal from different classes as i think the validation would have to happen there. the problem with the users is that some are english and some are german and therefore have different decimal Separators – XtremeBaumer May 03 '17 at 08:43
  • @AxelH its an price field and therefore the fraction should only allow 2 digits and not more – XtremeBaumer May 03 '17 at 09:10
  • @XtremeBaumer In financial, you have currencies with 3 digits (only a few) but also you can have price with 3, 6, 8 decimals. So this is not true everywhere unfortunatly. But this would work for a local system, like a store management or anything that doesn't handle fuel (3 decimal too) – AxelH May 03 '17 at 09:13
  • i think i can work with a maskformatter, but i cant seem to get the last thing to work which would be having the format `##.##` and still displaying values like `2.50`. if i use format `#.##` then i can't display values like `12.30`. if you can give me the tip to make this work id be very thankful – XtremeBaumer May 03 '17 at 09:39
  • You got my upvote for that; but unfortunately this is "too far away" from my current knowledge; and that would mean I have to start experimenting myself to find a solution (which might actually exist or not exist) ... and I fear my time so too limited to go for that today. – GhostCat May 03 '17 at 11:15