1

I need such a numeric text field on JFrame that

  1. restricts the input by a number with two digits after decimal point
  2. lays out the number separating every three digits i.e. 1 234 567,89.
  3. the number is displayed in correct format right away during typing

I tried using JFormattedTextField:

    NumberFormat nf = NumberFormat.getNumberInstance();
    nf.setMaximumFractionDigits(2);
    NumberFormatter numFormater = new NumberFormatter(nf);
    field1 = new javax.swing.JFormattedTextField(numFormater);

However, format restricitions apply only when focus leaves the component, which is a problem. I want user to be able to type only digits and delimeter in the field, and a space delimeter be placed right after each 3-d digit is entered in the field.

I can do this in C# just by specifing properties of the field. What is a clean way to do this in Swing? Thank you.

mKorbel
  • 109,525
  • 20
  • 134
  • 319

2 Answers2

6
  • one of ways is usage of InternationalFormatter which is additional Formatter for Number or DecimalFormatter

  • every restriction in JFormattedTextField has side effects for users input, e.g. Caret, Selection, etc.

  • proper of ways could be usage of combinations DocumentFilter with DocumentListener added to JFormattedTextField with plain Number or DecimalFormatter, without any restrictions, all workaround will be set in both DocumentFilter(designated for changes inside Document) with DocumentListener(outside of Document)

for example mentioned InternationalFormatter

import java.awt.*;
import java.math.*;
import java.text.*;
import javax.swing.*;
import javax.swing.JFormattedTextField.AbstractFormatter;
import javax.swing.JFormattedTextField.AbstractFormatterFactory;
import javax.swing.text.InternationalFormatter;

public class DocumentListenerAdapter {

    public DocumentListenerAdapter() {
        JFrame frame = new JFrame("AbstractTextField Test");
        final JFormattedTextField textField1 = new JFormattedTextField(new Float(10.01));
        textField1.setFormatterFactory(new AbstractFormatterFactory() {
            @Override
            public AbstractFormatter getFormatter(JFormattedTextField tf) {
                NumberFormat format = DecimalFormat.getInstance();
                format.setMinimumFractionDigits(2);
                format.setMaximumFractionDigits(2);
                format.setRoundingMode(RoundingMode.HALF_UP);
                InternationalFormatter formatter = new InternationalFormatter(format);
                formatter.setAllowsInvalid(false);
                formatter.setMinimum(0.0);
                formatter.setMaximum(1000.00);
                return formatter;
            }
        });
        NumberFormat numberFormat = NumberFormat.getNumberInstance();
        numberFormat.setMaximumFractionDigits(2);
        numberFormat.setMaximumFractionDigits(2);
        numberFormat.setRoundingMode(RoundingMode.HALF_UP);
        final JFormattedTextField textField2 = new JFormattedTextField(numberFormat);
        textField2.setValue(new Float(10.01));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(textField1, BorderLayout.NORTH);
        frame.add(textField2, BorderLayout.SOUTH);
        frame.setVisible(true);
        frame.pack();
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new DocumentListenerAdapter();
            }
        });
    }
}

for example JSpinner (editor is JFormattedTextField) with very simple DocumentFilter

Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Quite a complete answer +1 :) – Sage Nov 22 '13 at 10:48
  • @mKorbel there is a strange effect in this solution: after delimeter is added after 4-th, 7-th,... digits, the caret happens to be misplaced. If one types 123123123, the result of the input is 123 232 311,00 (Locale: ru). Unfortunately this is very inconvenient, and I suppose there is a bug in implementation somewhere? – user3021050 Nov 24 '13 at 19:12
0

How about adding a KeyListener to the field and reformatting whenever a key is typed?

Ross Drew
  • 8,163
  • 2
  • 41
  • 53
  • what is a proper way to invoke reformatting? Switching focus between components doesn't seem clean, and there is a problem of caret misplacement. – user3021050 Nov 24 '13 at 19:14