Search code examples
javaswing

How can I achieve a JFormattextfield accepting only number and limited character


I have two JFormattedTextField for variables Amount and Account No .
Purpose :

  1. Both field must accept only number
  2. Acc No can take up to 15 characters which can vary from 8-15. Similarly Amount can have up to 6 characters and also varies.

To achieve this I used MaskFormatter but the problem is the "Variation". Some acc is 15 digits, some are 12 digits so while using MaskFormatter limited to 15, it becomes mandatory to enter 15 digits otherwise inserted data disappears during runtime when we leave the JFormattedTextField

Is there any way to achieve both scenario in java swing?
Please suggest me


Solution

  • Use a DocumentFilter. Then you can customize the filter for your specific requirement.

    A basic example to get you started:

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.text.*;
    
    public class DigitFilter extends DocumentFilter
    {
        private int maxDigits;
    
        public DigitFilter(int maxDigits)
        {
            this.maxDigits = maxDigits;
        }
        @Override
        public void insertString(FilterBypass fb, int offset, String text, AttributeSet attributes)
            throws BadLocationException
        {
            replace(fb, offset, 0, text, attributes);
        }
    
        @Override
        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attributes)
            throws BadLocationException
        {
            //  In case someone tries to clear the Document by using setText(null)
    
            if (text == null)
                text = "";
    
            //  Build the text string assuming the replace of the text is successfull
    
            Document doc = fb.getDocument();
            StringBuilder sb = new StringBuilder();
            sb.append(doc.getText(0, doc.getLength()));
            sb.replace(offset, offset + length, text);
    
            if (validReplace(sb.toString()))
                super.replace(fb, offset, length, text, attributes);
            else
                Toolkit.getDefaultToolkit().beep();
        }
    
        private boolean validReplace(String text)
        {
            if (text.length() > maxDigits)
                return false;
    
            for (int i = 0; i < text.length(); i++)
            {
                if (! Character.isDigit( text.charAt(i) ) )
                    return false;
            }
    
            return true;
        }
    
        private static void createAndShowGUI()
        {
            JTextField textField = new JTextField(15);
            AbstractDocument doc = (AbstractDocument) textField.getDocument();
            doc.setDocumentFilter( new DigitFilter(5) );
    
            JFrame frame = new JFrame("Integer Filter");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout( new java.awt.GridBagLayout() );
            frame.add( textField );
            frame.setSize(220, 200);
            frame.setLocationByPlatform( true );
            frame.setVisible( true );
        }
    
        public static void main(String[] args) throws Exception
        {
            EventQueue.invokeLater( () -> createAndShowGUI() );
    /*
            EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    createAndShowGUI();
                }
            });
    */
        }
    
    }
    

    Read the section from the Swing tutorial on Implementing a Document Filter for an example of a filter that limits the number of characters. The logic from there needs to be combined with the example here.