[java] Restricting JTextField input to Integers

I know that this question must have been asked and answered a million times, but I just can't find an easy solution. I have a JTextField that is meant to accept only positive integers as input. I need a way to make sure that nothing else gets input here.

I already have a keyListener attached to this control. Removing the other code that this listener is there to handle, I have this:

       txtAnswer.addKeyListener(new KeyAdapter() {
        @Override
        public void keyPressed(KeyEvent e) {

            int key = e.getKeyCode();

            /* Restrict input to only integers */
            if (key < 96 && key > 105) e.setKeyChar('');
        };
    });

As you can see, I'm trying to use the the KeyCode to check whether the key just pressed falls within the range of integers. This seems to work. But what I want to do is to simply disregard the entry if it falls outside of this range. The code e.setKeyChar('') was meant to handle this, but it doesn't work. The code will compile, but it has no visible effect.

Can anybody tell me if I am on the right track? What can I replace e.setKeyChar('') with to make this work? Or am I totally going in the wrong direction?

Thanks.

This question is related to java swing numbers jtextfield

The answer is


Do not use a KeyListener for this as you'll miss much including pasting of text. Also a KeyListener is a very low-level construct and as such, should be avoided in Swing applications.

The solution has been described many times on SO: Use a DocumentFilter. There are several examples of this on this site, some written by me.

For example: using-documentfilter-filterbypass

Also for tutorial help, please look at: Implementing a DocumentFilter.

Edit

For instance:

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
import javax.swing.text.PlainDocument;

public class DocFilter {
   public static void main(String[] args) {
      JTextField textField = new JTextField(10);

      JPanel panel = new JPanel();
      panel.add(textField);

      PlainDocument doc = (PlainDocument) textField.getDocument();
      doc.setDocumentFilter(new MyIntFilter());


      JOptionPane.showMessageDialog(null, panel);
   }
}

class MyIntFilter extends DocumentFilter {
   @Override
   public void insertString(FilterBypass fb, int offset, String string,
         AttributeSet attr) throws BadLocationException {

      Document doc = fb.getDocument();
      StringBuilder sb = new StringBuilder();
      sb.append(doc.getText(0, doc.getLength()));
      sb.insert(offset, string);

      if (test(sb.toString())) {
         super.insertString(fb, offset, string, attr);
      } else {
         // warn the user and don't allow the insert
      }
   }

   private boolean test(String text) {
      try {
         Integer.parseInt(text);
         return true;
      } catch (NumberFormatException e) {
         return false;
      }
   }

   @Override
   public void replace(FilterBypass fb, int offset, int length, String text,
         AttributeSet attrs) throws BadLocationException {

      Document doc = fb.getDocument();
      StringBuilder sb = new StringBuilder();
      sb.append(doc.getText(0, doc.getLength()));
      sb.replace(offset, offset + length, text);

      if (test(sb.toString())) {
         super.replace(fb, offset, length, text, attrs);
      } else {
         // warn the user and don't allow the insert
      }

   }

   @Override
   public void remove(FilterBypass fb, int offset, int length)
         throws BadLocationException {
      Document doc = fb.getDocument();
      StringBuilder sb = new StringBuilder();
      sb.append(doc.getText(0, doc.getLength()));
      sb.delete(offset, offset + length);

      if (test(sb.toString())) {
         super.remove(fb, offset, length);
      } else {
         // warn the user and don't allow the insert
      }

   }
}

Why is this important?

  • What if the user uses copy and paste to insert data into the text component? A KeyListener can miss this?
  • You appear to be desiring to check that the data can represent an int. What if they enter numeric data that doesn't fit?
  • What if you want to allow the user to later enter double data? In scientific notation?

I can't believe I haven't found this simple solution anywhere on stack overflow yet, it is by far the most useful. Changing the Document or DocumentFilter does not work for JFormattedTextField. Peter Tseng's answer comes very close.

NumberFormat longFormat = NumberFormat.getIntegerInstance();

NumberFormatter numberFormatter = new NumberFormatter(longFormat);
numberFormatter.setValueClass(Long.class); //optional, ensures you will always get a long value
numberFormatter.setAllowsInvalid(false); //this is the key!!
numberFormatter.setMinimum(0l); //Optional

JFormattedTextField field = new JFormattedTextField(numberFormatter);

I used to use the Key Listener for this but I failed big time with that approach. Best approach as recommended already is to use a DocumentFilter. Below is a utility method I created for building textfields with only number input. Just beware that it'll also take single '.' character as well since it's usable for decimal input.

public static void installNumberCharacters(AbstractDocument document) {
        document.setDocumentFilter(new DocumentFilter() {
            @Override
            public void insertString(FilterBypass fb, int offset,
                    String string, AttributeSet attr)
                    throws BadLocationException {
                try {
                    if (string.equals(".")
                            && !fb.getDocument()
                                    .getText(0, fb.getDocument().getLength())
                                    .contains(".")) {
                        super.insertString(fb, offset, string, attr);
                        return;
                    }
                    Double.parseDouble(string);
                    super.insertString(fb, offset, string, attr);
                } catch (Exception e) {
                    Toolkit.getDefaultToolkit().beep();
                }

            }

            @Override
            public void replace(FilterBypass fb, int offset, int length,
                    String text, AttributeSet attrs)
                    throws BadLocationException {
                try {
                    if (text.equals(".")
                            && !fb.getDocument()
                                    .getText(0, fb.getDocument().getLength())
                                    .contains(".")) {
                        super.insertString(fb, offset, text, attrs);
                        return;
                    }
                    Double.parseDouble(text);
                    super.replace(fb, offset, length, text, attrs);
                } catch (Exception e) {
                    Toolkit.getDefaultToolkit().beep();
                }
            }
        });
    }

You can also use JFormattedTextField, which is much simpler to use. Example:

public static void main(String[] args) {
    NumberFormat format = NumberFormat.getInstance();
    NumberFormatter formatter = new NumberFormatter(format);
    formatter.setValueClass(Integer.class);
    formatter.setMinimum(0);
    formatter.setMaximum(Integer.MAX_VALUE);
    formatter.setAllowsInvalid(false);
    // If you want the value to be committed on each keystroke instead of focus lost
    formatter.setCommitsOnValidEdit(true);
    JFormattedTextField field = new JFormattedTextField(formatter);

    JOptionPane.showMessageDialog(null, field);

    // getValue() always returns something valid
    System.out.println(field.getValue());
}

When you type integer numbers to JtextField1 after key release it will go to inside try , for any other character it will throw NumberFormatException. If you set empty string to jTextField1 inside the catch so the user cannot type any other keys except positive numbers because JTextField1 will be cleared for each bad attempt.

 //Fields 
int x;
JTextField jTextField1;

 //Gui Code Here

private void jTextField1KeyReleased(java.awt.event.KeyEvent evt) {                                        
    try {
        x = Integer.parseInt(jTextField1.getText());
    } catch (NumberFormatException nfe) {
        jTextField1.setText("");
    }
}   

Here's one approach that uses a keylistener,but uses the keyChar (instead of the keyCode):

http://edenti.deis.unibo.it/utils/Java-tips/Validating%20numerical%20input%20in%20a%20JTextField.txt

 keyText.addKeyListener(new KeyAdapter() {
    public void keyTyped(KeyEvent e) {
      char c = e.getKeyChar();
      if (!((c >= '0') && (c <= '9') ||
         (c == KeyEvent.VK_BACK_SPACE) ||
         (c == KeyEvent.VK_DELETE))) {
        getToolkit().beep();
        e.consume();
      }
    }
  });

Another approach (which personally I find almost as over-complicated as Swing's JTree model) is to use Formatted Text Fields:

http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to swing

Calling another method java GUI Read input from a JOptionPane.showInputDialog box Call japplet from jframe Java JTable getting the data of the selected row What does .pack() do? How to add row of data to Jtable from values received from jtextfield and comboboxes How can I check that JButton is pressed? If the isEnable() is not work? Load arrayList data into JTable How to draw a circle with given X and Y coordinates as the middle spot of the circle? Simplest way to set image as JPanel background

Examples related to numbers

how to display a javascript var in html body How to label scatterplot points by name? Allow 2 decimal places in <input type="number"> Why does the html input with type "number" allow the letter 'e' to be entered in the field? Explanation on Integer.MAX_VALUE and Integer.MIN_VALUE to find min and max value in an array Input type "number" won't resize C++ - how to find the length of an integer How to Generate a random number of fixed length using JavaScript? How do you check in python whether a string contains only numbers? Turn a single number into single digits Python

Examples related to jtextfield

Java - Check if JTextField is empty or not How to set the height and the width of a textfield in Java? getting integer values from textfield Restricting JTextField input to Integers Limiting the number of characters in a JTextField JTable - Selected Row click event How to Set Focus on JTextField? How to convert JTextField to String and String to JTextField? How to clear the JTextField by clicking JButton Detect enter press in JTextField