0

I'm trying to restrict the characters' number in a JFormattedTextField. I'm using a regular expression to validate the field but I need to limit the input too.

I tried DocumentFilter and PlainDocument but it didn't work. Here is my code:

public class UsingRegexFormatter {

public static void main(String[] a) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JFormattedTextField formattedField = new JFormattedTextField(new RegexFormatter("[0-9]+([,\\.][0-9]+)*"));
    //trying to limit to 3 characters with no success...
    formattedField.setDocument(new JTextFieldLimit(3));
    frame.add(formattedField, "North");

    frame.add(new JTextField(), "South");

    frame.setSize(300, 200);
    frame.setVisible(true);
}

static class JTextFieldLimit extends PlainDocument {

    private int limit;

    public JTextFieldLimit(int limit) {
        super();
        this.limit = limit;
    }

    public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException {
        if (str == null) {
            return;
        }

        if ((getLength() + str.length()) <= limit) {
            super.insertString(offset, str, attr);
        }
    }
}

static class RegexFormatter extends DefaultFormatter {

    private Pattern pattern;

    private Matcher matcher;

    public RegexFormatter() {
        super();
    }

    /**
     * Creates a regular expression based AbstractFormatter. pattern
     * specifies the regular expression that will be used to determine if a
     * value is legal.
     */
    public RegexFormatter(String pattern) throws PatternSyntaxException {
        this();
        setPattern(Pattern.compile(pattern));
    }

    /**
     * Creates a regular expression based AbstractFormatter. pattern
     * specifies the regular expression that will be used to determine if a
     * value is legal.
     */
    public RegexFormatter(Pattern pattern) {
        this();
        setPattern(pattern);
    }

    /**
     * Sets the pattern that will be used to determine if a value is legal.
     */
    public void setPattern(Pattern pattern) {
        this.pattern = pattern;
    }

    /**
     * Returns the Pattern used to determine if a value is legal.
     */
    public Pattern getPattern() {
        return pattern;
    }

    /**
     * Sets the Matcher used in the most recent test if a value is legal.
     */
    protected void setMatcher(Matcher matcher) {
        this.matcher = matcher;
    }

    /**
     * Returns the Matcher from the most test.
     */
    protected Matcher getMatcher() {
        return matcher;
    }

    public Object stringToValue(String text) throws ParseException {
        Pattern pattern = getPattern();

        if (pattern != null) {
            Matcher matcher = pattern.matcher(text);

            if (matcher.matches()) {
                setMatcher(matcher);
                return super.stringToValue(text);
            }
            throw new ParseException("Pattern did not match", 0);
        }
        return text;
    }
}
}

Thank you so much

mKorbel
  • 109,525
  • 20
  • 134
  • 319
michael laudrup
  • 27
  • 3
  • 10
  • `PlainDocument` is not a `DocumentFilter` – MadProgrammer Nov 28 '14 at 00:50
  • `JFormattedTextField` is one of those annoying classes which installs it's own filter or `Document` in order to facilitate it's functionality, but only does so after it's added to the UI...:P – MadProgrammer Nov 28 '14 at 01:02
  • I meant I tried both DocumentFilter and PlainDocument, it didn't work anyway.. – michael laudrup Nov 28 '14 at 01:14
  • I seem to recall that the look and feel installs it's own `Document` or something, but something messing about with it... :P – MadProgrammer Nov 28 '14 at 01:16
  • Okay, when focused, the `JFormattedTextField` installs it's own `DocumentFilter`...which is a complete pain. `JFormattedTextField` really don't do real time filtering and does it's validation when the field loses focus or is actioned... – MadProgrammer Nov 28 '14 at 01:35
  • Or you could just allow an infinite number of characters, and just mark the input as invalid. Might be less confusing to the user compared to suddenly not reacting on key strokes. Such solution can be implemented using a `java.text.Format` set on the `JFormattedTextField` as shown [here](http://stackoverflow.com/a/13424140/1076463) – Robin Nov 29 '14 at 10:10

2 Answers2

0

Besides implementing your own JFormattedTextField class, a possible workaround would be to use a maskformatter and then just use * as the delimiter to allow for any character

MaskFormatter formatter = new MaskFormatter("************"); //with however many characters you need

formatter.setValidCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");`// whatever characters you would use

JFormattedTextField textField = new JFormattedTextField(formatter); 

original post: http://www.javalobby.org/java/forums/t48584.html

  • Then maybe use regular textfields and limit the characters that way. You should be able to validate the information with a custom class that implements the regular expression validation class. unless your trying to do it dynamically. Here are some links I came upon researching this matter: http://stackoverflow.com/questions/15269507/how-to-validate-a-jtextfield-of-email-id-with-a-regex-in-swing-code http://stackoverflow.com/questions/3537093/limit-number-of-characters-in-jtextfield –  Nov 28 '14 at 02:09
  • Well, I did it by overriding getDocumentFilter() method in RegexFormatter to get my own documentFilter, thank you :) – michael laudrup Nov 28 '14 at 20:19
0

Easiest way is to override the keyTyped() event to throw away characters after a certain limit. Here's a simple example from a GuessingGame I use in my courses:

txtGuess = new JTextField();
txtGuess.addKeyListener(new KeyAdapter() {
    public void keyTyped(KeyEvent e) { 
        if (txtGuess.getText().length() >= 3 ) // limit textfield to 3 characters
            e.consume(); 
    }  
});

This limits the number of characters in a guessing game text field to 3 characters, by overriding the keyTyped event and checking to see if the textfield already has 3 characters - if so, you're "consuming" the key event (e) so that it doesn't get processed like normal.

Hope it helps a bit - just a different approach. Cheers!