Tuesday, June 20, 2006

Using JFormattedTextField for integers

I discovered the hard way that:

new JFormattedTextField(new Integer(0))

does not do what I wanted.

What I wanted was to have a text entry field restricted to integers. What I got was a field which rounded off numbers to integers. This was surprising.

After a while of poking at it, I tried using various incarnations of NumberFormat and DecimalFormat in the field constructor with no luck. Perusing the sources was not particularly illuminating either, at least at first.

Finally I noticed that JFormattedTextField.getDefaultFormatterFactory(Object) contained this legerdemain:

if (type instanceof DateFormat) { ... }
if (type instanceof NumberFormat) { ... }
if (type instanceof Format) { ... }
if (type instanceof Date) { ... }
if (type instanceof Number) { /* mucking around with formatter factory */ }

Hmmm. So in a flash of inspiration I tried:

new JFormattedTextField(new BigInteger(0))
and it worked, although I do not entirely understand why. JFormattedTextField maintains separately value, formatter and formatter factory in addition to the document model for text entry and a lot of state options for handling valid and invalid input.

I'm sure its a tour de force for someone at Sun, and most importantly the class works, but quirks like this one are difficult to find and explain.

UPDATE: A colleague of mine asked for more details on this point. To clarify:

Argument Input Behavior
new Integer(0) 3.0 3
3.3 3
new BigInteger(0) 3.0 3
3.3 invalid

So to get non-integral input to be treated as invalid, you must initialize JFormattedTextField with a BigInteger; initializing with an Integer gets a rounding mode instead.

No comments: