Asked  7 Months ago    Answers:  5   Viewed   73 times

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.

 Answers

61

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?
Tuesday, June 1, 2021
 
TheCarver
answered 7 Months ago
62

Take a look at this one: http://code.google.com/p/xswingx/

It is not very difficult to implement it by yourself, btw. A couple of listeners and custom renderer and voila.

Wednesday, June 2, 2021
 
Parfait
answered 7 Months ago
66

maybe better would be use DocumentFilter with Pattern,

Tuesday, August 24, 2021
 
Vincent Stimper
answered 4 Months ago
51

DocumentListeners do not permit the modification of the underlying document of the JTextComponent. You are looking for a DocumentFilter.

Example

Monday, November 22, 2021
 
ClmentM
answered 2 Weeks ago
52

You'll need to either parse the string yourself (the ast module would probably be useful), or use eval:

>>> s = '6*pi'
>>> eval(s,{'__builtins__': None, 'pi': np.pi})
18.84955592153876

Note that there are some nasty things that users can do with eval. My solution protects you from most of them, but not all -- pre-checking the string to make sure that there aren't any __ will make it even safer (that eliminates all of the vulnerabilities that I know of, but there could be others)

Sunday, December 5, 2021
 
KingCrunch
answered 2 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share