如何在用户输入时限制JTextPane中字符的数量(Java)

4

我需要在输入X个字符后禁止输入更多的字符。我需要在输入X个字符后发出嘟嘟声。我知道如何在用户按下enter键后执行此操作,但我需要在用户按下enter键之前执行此操作。从Oracle网站中找到的方法是将DocumentSizeFilter添加到JTextPane中。但是我无法让它在用户超过字符限制时通知他们(它只能在用户按下enter键后才起作用)。以下是我的代码示例。

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 ));

}

2
渲染器永远不会发出嘟嘟声 ;-) 确保你理解了渲染器与编辑器之间的概念。 - kleopatra
4个回答

6

JTextPane 中文档的 insertString 方法覆盖,使其在达到最大字符数后不再插入任何字符。

例如:

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();
        }
    }
});

更新:

您可以按以下方式更改您的类:

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();
                }
            }
        });
    }
}

1
+1,对于更简短的方法,我本来要通过我的回答告诉他整本圣经,而你只用了一个方法 :-) 问候 - nIcE cOw
非常抱歉我很菜,但是这段代码在哪里使用?我的类EndCycleTextAreaRenderer是否应该覆盖insertString方法? - Boundless
@Boundless,请查看我的更新,了解如何更新你的类。 - dogbane
@Boundless 对我来说它是有效的。我所做的就是在 JPanel 中添加一个 new EndCycleTextAreaRenderer(),然后我就得到了期望的行为。你需要展示更多的代码,这样我们才能看到你是如何使用它的。 - dogbane
3
不要子类化文本组件(相对于文档,甚至更好地使用DocumentFilter),以避免不必要的麻烦。 - kleopatra
显示剩余2条评论

2

这里有一个示例程序,当您第四次输入到TextPane时,它会哔哔地发出声音,即使您没有按下Enter键:

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();
   }
}

希望这能有所帮助。

是的,我尝试了Oracle网站上的这个例子,但用户按键时并没有得到所需的蜂鸣声。 - Boundless
@Boundless:请检查一下我刚刚制作的程序,这里您不需要按任何回车键就可以发出蜂鸣声。只需尝试添加第四个字符即可发出蜂鸣声。祝好! - nIcE cOw
我试过了,它按照需要的方式工作。谢谢,我会尝试将其用于我的需求。 - Boundless
所以,当我将这个解决方案与我的代码实现时,它并没有按照预期工作。肯定有些东西我漏掉了。我的类被用作TableCellRenderer。这可能会导致代码出错吗?如果是这样,你知道如何修复它吗? - Boundless
@Boundless:如果你仍然遇到问题,我建议你将我的答案作为适当的答案删除,或者重新提出这个问题,因为我不确定TableCellRenderer如何阻碍代码流程。问候 - nIcE cOw

0
我建议通过添加keyReleasedListener检查每个键入的字符数,这是我最近在GUI中使用的一种方法,可以似乎立即检查范围并在用户输入时显示错误。
以下是我如何在一个文本字段中实现它的方式:
carbonTextField.addKeyListener(new java.awt.event.KeyAdapter() 
{
        public void keyReleased(java.awt.event.KeyEvent evt) 
        {
            carbonTextFieldKeyReleased(evt);
        }
});

你是指自定义的KeyListener吗? - Boundless
我编辑了原始帖子,展示了如何添加keyReleased监听器。这样可以让你每次检查边界(本质上允许你在每个按键时进入自己的方法,从而允许你检查是否发出蜂鸣声)。 - Alex
+1 对于你提供的信息表示认同,毫无疑问很不错,但现在通常不建议在Swing中使用KeyEvents。敬礼。 - nIcE cOw
对于keyListener,那只是错误的方法(不完整且过于低级)。 - kleopatra

0
检查以下代码:
txtpnDesc.addKeyListener(new KeyAdapter() {
        @Override
        public void keyTyped(KeyEvent e) {
            if(txtpnDesc.getText().length() == 30)
            {
                e.consume();
            }

        }
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接