4

I need to not allow any characters to be entered after X have been typed. I need to send a beep after X characters have been typed. I know how to do this after the user presses enter, but I need to do it before the user presses enter. The approach I found from Oracle's site is to add a DocumentSizeFilter to the JTextPane. I can't get this to notify the user when they have gone over (it doesn't work until they press enter). This is a sample of what I have.

public class EndCycleTextAreaRenderer extends JTextPane
implements TableCellRenderer {

private final int maxNumberOfCharacters = 200;

public EndCycleTextAreaRenderer() {
    StyledDocument styledDoc = this.getStyledDocument();
    AbstractDocument doc;
    doc = (AbstractDocument)styledDoc;
    doc.setDocumentFilter(new DocumentSizeFilter(maxNumberOfCharacters ));

}
kleopatra
  • 51,061
  • 28
  • 99
  • 211
Boundless
  • 2,444
  • 2
  • 25
  • 40

4 Answers4

6

Override the insertString method of the document in the JTextPane so that it doesn't insert any more characters once the maximum has been reached.

For example:

JTextPane textPane = new JTextPane(new DefaultStyledDocument() {
    @Override
    public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
        if ((getLength() + str.length()) <= maxNumberOfCharacters) {
            super.insertString(offs, str, a);
        }
        else {
            Toolkit.getDefaultToolkit().beep();
        }
    }
});

Update:

You can change your class as follows:

public class EndCycleTextAreaRenderer extends JTextPane implements TableCellRenderer {

    private final int maxNumberOfCharacters = 200;

    public EndCycleTextAreaRenderer() {
        setStyledDocument(new DefaultStyledDocument() {
            @Override
            public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
                if ((getLength() + str.length()) <= maxNumberOfCharacters) {
                    super.insertString(offs, str, a);
                } else {
                    Toolkit.getDefaultToolkit().beep();
                }
            }
        });
    }
}
dogbane
  • 266,786
  • 75
  • 396
  • 414
  • 1
    +1, for the shorter approach, I was about to tell him the whole Bible, through my Answer, what you did in one method :-) Regards – nIcE cOw Jan 16 '12 at 16:59
  • I'm sorry for being such a noob, but where do I use this code? Is my class EndCycleTextAreaRenderer supposed to override insertString? – Boundless Jan 16 '12 at 17:04
  • @Boundless check my update to see how you can update your class. – dogbane Jan 16 '12 at 17:19
  • @dogbane Thanks for the help. I am still getting the same behavior (where the user can type as much as they want, but when they press enter the text is then truncated). I stuck a breakpoint in and the Toolkit.getDefaultToolkit().beep() call only happens after the user presses enter. – Boundless Jan 16 '12 at 19:10
  • @Boundless it works for me. All I did was add a `new EndCycleTextAreaRenderer()` to a JPanel and I get the desired behaviour. You'll have to show more code so we can see how you are using it. – dogbane Jan 17 '12 at 08:47
  • 3
    -1 for subclassing the text components (vs. the document or even better simply using a DocumentFilter) – kleopatra Jan 17 '12 at 10:44
  • note: for `JEditorPane`s, you'll have to use `.setDocument()` – phil294 Apr 02 '15 at 19:46
2

Here is a sample program, for you where, as you enter the fourth time into the TextPane it will beep, without even you pressing the Enter key:

import javax.swing.*;
import javax.swing.text.*;

import java.awt.Toolkit;

public class TextPaneLimit extends JFrame
{
    private JPanel panel;
    private JTextPane tpane;
    private AbstractDocument abDoc;

    public TextPaneLimit()
    {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        panel = new JPanel();
        tpane = new JTextPane();

        Document doc = tpane.getStyledDocument();
        if (doc instanceof AbstractDocument) 
        {    
            abDoc = (AbstractDocument)doc;
            abDoc.setDocumentFilter(new DocumentSizeFilter(3));
        }

        panel.add(tpane);

        add(panel);
        pack();
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
            {
                public void run()
                {
                    new TextPaneLimit().setVisible(true);
                }
            });
    }
}

class DocumentSizeFilter extends DocumentFilter {

   private int max_Characters;
   private boolean DEBUG;

   public DocumentSizeFilter(int max_Chars) {

      max_Characters = max_Chars;
      DEBUG = false;
   }

   public void insertString(FilterBypass fb
                            , int offset
                              , String str
                                , AttributeSet a) 
   throws BadLocationException {

      if (DEBUG) {

         System.out.println("In DocumentSizeFilter's insertString method");
      }

      if ((fb.getDocument().getLength() + str.length()) <= max_Characters) 
         super.insertString(fb, offset, str, a);
      else 
         Toolkit.getDefaultToolkit().beep();
   }

   public void replace(FilterBypass fb
                       , int offset, int length
                       , String str, AttributeSet a)
   throws BadLocationException {

      if (DEBUG) {
         System.out.println("In DocumentSizeFilter's replace method");
      }
      if ((fb.getDocument().getLength() + str.length()
           - length) <= max_Characters) 
         super.replace(fb, offset, length, str, a);
      else
         Toolkit.getDefaultToolkit().beep();
   }
}

Hope this might help.

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
nIcE cOw
  • 24,468
  • 7
  • 50
  • 143
  • Yes, I tried this example from Oracle's site with no luck of the desired beep as the user presses a key. – Boundless Jan 16 '12 at 19:12
  • @Boundless : Do check this program, i just made, here you don't have to press any Enter key for beep to happen. Simply try to add the fourth character and it will beep. Regards – nIcE cOw Jan 16 '12 at 19:40
  • I tried it, and it works as needed. Thank you, I'll try using it for my needs. – Boundless Jan 16 '12 at 19:48
  • So, again when I implement this solution with my code it doesn't work as intended. There has to be something that I'm missing. My class is being used as a TableCellRenderer. Could that break the code? If so, do you know how to fix it? – Boundless Jan 16 '12 at 19:56
  • @Boundless : If still you facing issues, I will suggest you remove my answer as the appropriate answer or else, ask this question again, since I am not sure how TableCellRenderer can hamper the code flow. Regards – nIcE cOw Jan 16 '12 at 20:03
0

Check the following code:

txtpnDesc.addKeyListener(new KeyAdapter() {

        @Override
        public void keyTyped(KeyEvent e) {
            if(txtpnDesc.getText().length() == 30)
            {
                e.consume();
            }

        }
    });
0

I would suggest checking the # of characters with every key entered by adding a keyReleasedListener, it is something I used in a recent GUI of mine to check bounds seemingly instantly and display errors to the user as they typed.

Here is how I implemented it on one of my TextFields:

carbonTextField.addKeyListener(new java.awt.event.KeyAdapter() 
{
        public void keyReleased(java.awt.event.KeyEvent evt) 
        {
            carbonTextFieldKeyReleased(evt);
        }
});
Alex
  • 2,405
  • 4
  • 23
  • 36
  • Do you mean a custom keyListener? – Boundless Jan 16 '12 at 16:51
  • I edited my original post to show how I added a keyReleased Listener. This allows you to check your bounds each time (essentially allowing you into your own method each keyPress, which will allow you to check for the beep or not.) – Alex Jan 16 '12 at 16:55
  • +1 for the info that you had given, no doubt it's good, but now using KeyEvents with Swing is generally not a good idea. Regards – nIcE cOw Jan 16 '12 at 17:10
  • -1 for keyListener, that's simply the wrong approach (incomplete _and_ far too low-level – kleopatra Jan 17 '12 at 10:42