I have a numeric JSpinner which accepts values in a specific measuring unit. Now, I'd like to have a special JSpinner behavior: If a user enters a numeric value and appends a specific measuring unit string (e.g. "inch", "pica") then the entered numeric value must be converted into another value (depending on the unit string). This conversion must occur when user leaves the spinner field (focus lost) or if a "commitEdit" occurs in any way.
I've tried several variants: Custom document filter, custom format instance and custom text field document for the spinner's JFormattedTextField. But I didn't find any possibility to "hook" the "commitEdit" method invocation of JFormattedTextField.
What's the best approach to implement my requirements? Is there an easy way doing that?
There is also something else that enables you to modify the user input before it becomes commited: It is the
commitEditmethod itself (of theJFormattedTextFieldof theDefaultEditorof theJSpinner). Inside thecommitEdityou can see that the methodstringToValueof theJFormattedTextField'sAbstractFormatteris called. Which means that if you give your own customAbstractFormatterto the text field it can convert any string to a value and a value to any string. Here is where the exceptions occur to indicate if the commit failed or not.So, follows a custom
AbstractFormatterhandling different units, as you requested:I used units measuring length (millimeters, inches, feet and yards). But you can adapt this to your own needs.
Note in the above implementation the
SpinnerNumberModelonly knows millimeters. TheAbstractFormatterhandles converting millimeters to ther units and back (as per the user's input). That means that when you set the units to YD (ie yards) the model will still spin at millimeters but theJFormattedTextFieldis going to spin at fractions of yards. Try it out to see yourself what I mean. That means thatgetValue()of theJSpinner/SpinnerNumberModelwill always return the amount of millimeters no matter what the units are in the text field (theAbstractFormatterwill always do the conversions).As a second scenario, if you want, you can move the conversion outside the
AbstractFormatter. You can, for example, let the user input a value in the spinner which will always be independent from the measuring unit. This way the user always sees value spinning with step equal to 1 (in this example) and meanwhile theAbstractFormatterwill hold a property of the last unit set to the spinner by the user. So now when you get the value from theJSpinner/SpinnerNumberModelyou will get a number independent from units and then use the last unit set to theAbstractFormatterto determine what units the user means. This is a bit different and maybe more convenient way to use the spinner.Here is the code for the second case:
As for the locale thing you said, if I understood correctly, you want commas and dots to both operate in the same spinner? If so, you can check the answer here which is about exactly that. In that case again the problem is solved by using a custom
AbstractFormatter.