JTextField and DocumentFilter: how to limit document length by having extra characters drop off the end of the string

48 views Asked by At

I have been looking through a lot of DocumentFilter examples, and have realized that my needs are a bit unusual:

  • Three characters, maximum
  • Only digits, 0-9, nothing else
  • Automatically zero-filled to the left

And it’s these three requirements together that I am having problems with, particularly the maximum length issue.

Most examples I have seen simply stop extra characters from being added, usually with a system beep. But I cannot prevent characters from being added, because with the very first numerical character, the entire string will get zero-filled. So adding another two numbers would be a no-go if the objective of the code is to prevent additional characters from being entered once the string hits maximum length, because even with the first number there will be two zeros added in front of it.

In my case, that zero-filled content needs to drop off the left side of the string. And this can continue even if the user continues adding numbers - any character which is in the fourth (or more) position from the right needs to be disposed of. The problem is, the numbers dropping off are (likely) the ones in the document, and not the ones being added.

From what I understand, the sequence of actions I need to complete is as follows:

  1. Grab the inserted/added content
  2. Filter out/replace non-numerical content (as desired)
  3. Call the original content (from the document)
  4. Insert the new content into the original content
  5. Hold this content temporarily (outside of the document)
  6. Trim or pad the temporary content appropriately, depending on length
  7. Wipe the document entirely
  8. Add the entire temporary content to the document

Because the trim/pad occurs on the entire content and not just the newly-added content, we need to do this on the entire document. We cannot do this to only the characters that have been added or pasted into the document.

Right now, my best attempt is as follows:

@Override
public void replace( FilterBypass fb
        , int offset
        , int length
        , String text
        , AttributeSet attributes ) throws BadLocationException {
    int editedLength = fb.getDocument().getLength() + text.length();
    int exceedsLength = editedLength - maxLength;
    String content = sanitizeNumeric( text.trim() );

    // Temporarily update the document
    fb.replace( offset
            , length
            , content
            , attributes );

    // If the document exceeds the maximum allowable length, trim it.
    if ( exceedsLength > 0 ) {
        String fullString = fb.getDocument().getText( 0, editedLength - 1 );
        String trimmedString = trimSide( fullString, exceedsLength );

        // Clear the original document - essentially, everything in the JTextField
        super.remove( fb
                , 0
                , editedLength - 1 );

        // Overwrite with the temporary padded/trimmed document
        super.insertString( fb
                , 0
                , trimmedString
                , attributes);
    }
}

My issue occurs in the lower half - when doing the fb.replace, is the fb.getDocument().getText( 0, editedLength - 1 ); further down accessing this new, combined document, or is it accessing the old document that does not have the newly-entered characters?

Please note that this does not yet have the zero-fill padding, I am just trying to hash it out such that a fourth character entered anywhere in the document causes the left-hand-most character to drop off of the document. I am not trying to prevent a fourth character from being added, only that its addition bumps everything left to it over, and bumps the one furthest left clear off of the document.

TL;DR: I may not have a complete grasp on what FilterBypass does or represents.

1

There are 1 answers

2
camickr On

Check out: https://stackoverflow.com/a/44207361/131872 for an example that might get you started.

The code as posted will:

  1. only allow you to enter digits on the right
  2. allow you to enter unlimited number of digits.

The example uses a StringBuffer to build the text to insert into the Document.

It is not exactly what you want but I think you can use its concepts to implement your requirement.

First test the code as is to understand how it works. You would use:

DecimalFormat format = new DecimalFormat("000");

to provide default formatting with leading zeros.

Then, to limit the digits entered, you can remove the excess digits in the StringBuffer in the replace(...) method:

sb.append(str);

if (sb.length() > 3)
    sb.delete(0, sb.length() - 3);

Other changes you will need to make:

  1. you don't need the "decimal point" logic
  2. you want the ability to insert characters at any point in the string. You will need to change the sb.append(...) logic.

I haven't tested it but I assume you can just use:

sb.insert(offs, str);