Max Length on JTextField Using DocumentFilter: A Step by Step tutorial

  

  Have you ever tried to make a textfield that accepts only 20 characters? Or a text area that automatically converts the user typed letters to upper case? Swing’s Document Listener is the most accurate and hassle-free way to achieve this in Swing. This articles explains you what you need to get started with Document Filter. Step by Step.

Let’s Make a MaxTextField

Let’s start by defining the problem. We are trying to add a TextField that will accept only 20 characters. After typing 20 characters the user cannot enter any more characters either by keypress or copy-paste. The user can however, delete existing characters and type new ones as long as the total number of characters is less than or equal to 20.

The Dirty way: Using KeyEvent.consume()

One’s first reaction would be to add a key listener to the textfield and calling the consume() method in a listener method like keyTyped() when the no. of characters exceeds 20.

Here’s the sample code that one would be templted to right

//Assume that textField is an instance of JTextField
textField.addKeyListener(new KeyAdapter(){
 public void keyTyped(KeyEvent e) {
  if(textField.getText().length() > 20){
  //Consume if the user has typed more than 20 charactes
  e.consume();
 }
}
}

This would seem to work fine. But there’s a catch. after typing 20 characters, the user can still insert more characters in the textfield by copy-pasting the text!!! why does this not work? Because, the paste happens at keyPress not keyTyped.
So, what’s the solution? We could add code in the keyPressed() that could handle ctrl+v. But what about shift+ins? What about right click and paste?
Started Sounding messy right? But the most itchy part of using this technique is this. When multiple keylisteners are attached to a textfield, there is no guarantee that which one will be called first. so, calling consume() on one listener does not prevent other listener from seeing this event! So when one listener is preventing the data from being entered, the other listener might happily be checking the spelling and underline the word in red(for a wrong spelling) even thought the user sees no character typed!!!

Enter DocumentFilter

What follows from the above discussion is this

“We need a technique that prevents more than 20 characters from being entered in the textfield before it reaches the textfield, not a technique that removes the character after it’s already there”

The solution is to use a document filter. What’s a document filter? Before that, What’s a document in the first place? A document is something like a container that sort-of stores the text entered in any text component in Swing. Each text component in swing has it’s own Document. It’s kind of a model for the swing-text-based-ui components. Got it?
Ok, so now what’s a DocumentFilter? Simple. A document filter is a special class that can be attached to documents to filter out the data before it goes into the document.

How to implement a DocumentFilter:

You simply follow the following steps

  • Write a class extending the DocumentFilter class
  • override one or many of insertString(), remove() or replace() methods, depending on whether you are filtering string insertion, string removal or string-replacement operations.
  • you grab the document of the textfield and attach an instance of this document filter to that document

Let’s start. Here’s the DocumentFilter class for our problem. Clearly we need to override the insertString() and replace() methods so that user may not enter more than 20 characters why inserting or replacing strings. Here’s the code. See comments for more details

Step 1) Writing the class:

class MyDocumentFilter extends DocumentFilter{
 public void replace(FilterBypass fb, int offset, int length,
      String text, AttributeSet attrs) throws BadLocationException {
 
 //The current length minus the no.of characters deleted plus the
 // number of characters inserted is the final length in the textfield
 //and should not be more than 20
 if ((fb.getDocument().getLength() + text.length() - length) <= 20){
	super.replace(fb, offset,length, text, attrs);
 }
 else{
 	//Let's beep if the user tries to enter more characters
 	Toolkit.getDefaultToolkit().beep();
 }
}
public void insertString(FilterBypass fb, int offset,
       String string, AttributeSet attr) throws BadLocationException {
 
  //While inserting the current length plus the number of characters inserted
  //is the final length in the textfield and should not be more than 20
  if ((fb.getDocument().getLength() + string.length()) <= 20){
    super.insertString(fb, offset,string, attr);
  }
  else{
    //Let's beep if the user tries to enter more characters
   Toolkit.getDefaultToolkit().beep();
  }
 }
}

Step 2) Attach an instance of this class to the textfields document.

This is a simple and one line code as below

((AbstractDocument)textField.getDocument())
.setDocumentFilter(new MyDocumentFilter());

A small point to note is that we need to cast the return type of getDocument() to AbstractDocument, only which has the setDocumentFilter method.

That’s it! Hope you found this article interesting.







6 Responses to 'Max Length on JTextField Using DocumentFilter: A Step by Step tutorial'

  1. Swing links of the week: July 27, 2008 : Pushing Pixels - July 28th, 2008 at 5:04 pm

    […] has a number of useful tutorials on using the JTextField and related classes, including the introduction to DocumentFilter to enforce upper limit on the number of characters, auto-conversion to upper […]

  2. Steve - July 29th, 2008 at 3:18 pm

    Why not override the Document the textfield uses rather than the filter ? For instance

    public class MaxLengthDocument extends PlainDocument {

    /**
    * Maximum length of the text
    */
    private final int maxLength;

    /**
    * Default constructor.
    *
    * @param maxLength
    * the maximum number of characters that can be entered in the
    * field
    */
    public MaxLengthDocument(final int maxLength) {
    super();
    this.maxLength = maxLength;
    }

    public void insertString(final int offset, final String str,
    final AttributeSet attr) throws BadLocationException {
    if (getLength() + str.length() > maxLength) {
    Toolkit.getDefaultToolkit().beep();
    return;
    }
    super.insertString(offset, str, attr);
    }

    }

  3. Steve - July 29th, 2008 at 3:28 pm

    On a related note I created a Regex Document a while ago which I use now and again for fields that have tricky formats.

    public class RegexDocument extends MaxLengthDocument {

    protected final Pattern pattern;

    /**
    * Contructor used to construct a document object which pattern matches
    * strings as typed.
    *
    * @param regex
    * pattern to match on typed strings
    * @param maxLength
    * maximum length of full string
    */
    public RegexDocument(final String regex, final int maxLength) {
    super(maxLength);
    this.pattern = Pattern.compile(regex);
    }

    public void insertString(final int offset, final String str,
    final AttributeSet attr) throws BadLocationException {
    final Matcher matcher = pattern.matcher(str);
    if (matcher.matches()) {
    super.insertString(offset, str, attr);
    } else {
    Toolkit.getDefaultToolkit().beep();
    }
    }

    }

    I used it with calls like this:

    xxxTF.setDocument(new RegexDocument(”[a-zA-Z0-9]+”, 20));

    Steve

  4. Kaushik - July 29th, 2008 at 4:25 pm

    Steve,
    Thanks for the comment. Yes, writing your own document is another way to achieve this. One small advantage of a document filter might be that ,this can be attached to multiple components that requires different kinds of documents. Having a subclass of apart from PlainDocument will mandate that these components should have a PlainDocument attached to them and wouldn’t be usable by components that uses other kinds of documents like “HTMLDocument” for example.
    Your example of “RegexDocument” was good too.
    thanks,
    Kaushik

  5. Steve - July 29th, 2008 at 4:45 pm

    Yep very true Kaushik there are a few restrictions with using the PlainDocument. In my case it wasn’t a big deal but could be if you wanted a more flexible approach.

    I’ve found that once you get your basic approach setup like the examples you give from then on its very easy to add smart functionality to your code to allow various nice gui tricks.

  6. Big boobs clips movies free. - August 17th, 2008 at 12:49 am

    Big boobs free movies….

    Big oiled boobs movies. Boobvision big black boobs movies. Big boobs clips movies free. Free big boobs movies. Big boobs free movies….


Leave a Reply





Popular Articles

Blog Categories

Monthly Archives

Resources