限制JTextField中的字符数

30

我想设置JTextField的最大长度,以便您不能输入超过限制的字符数。这是我目前的代码...

    textField = new JTextField();
    textField.setBounds(40, 39, 105, 20);
    contentPane.add(textField);
    textField.setColumns(10);

有没有简单的方法来限制字符数量?


2
永远不要使用setBounds。而是使用一个布局管理器(在字段的父级中),该管理器根据需要定位/调整组件的大小。 - kleopatra
1
从Java 1.4开始,实现这种结果的推荐方法是使用DocumentFilter,所有其他解决方案都是在DocumentFilter可用之前设计的“hack”或“work arounds”,大多数情况下应该被忽略。 - MadProgrammer
9个回答

30

您可以像这样做(参考自这里):

import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

class JTextFieldLimit extends PlainDocument {
  private int limit;
  JTextFieldLimit(int limit) {
    super();
    this.limit = limit;
  }

  JTextFieldLimit(int limit, boolean upper) {
    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);
    }
  }
}

public class Main extends JFrame {
  JTextField textfield1;

  JLabel label1;

  public void init() {
    setLayout(new FlowLayout());
    label1 = new JLabel("max 10 chars");
    textfield1 = new JTextField(15);
    add(label1);
    add(textfield1);
    textfield1.setDocument(new JTextFieldLimit(10));

    setSize(300,300);
    setVisible(true);
  }
}

编辑:请查看这个之前的 SO 帖子。您可以拦截键盘按键事件,并根据文本字段中当前字符数量添加/忽略它们。


1
有没有更简单的方式可以从JFrame中选择? - user1326088
-1 对于编辑:拦截关键事件(也称使用keyListener)不是正确的方法... - kleopatra
3
为什么你需要另一个解决方案?原来的那个是可行的。它简单易懂,对于每个新的文本字段都可以重复使用。当拦截键事件时,你仍然可以将非常长的文本粘贴到字段中,绕过字符限制。 - moeTi
2
不再需要覆盖或扩展Document来实现这一点,DocumentFilter API(自Java 1.4起)已经取代了在Java 1.3中进行的几乎所有其他“解决方法”或“黑客”。 - MadProgrammer
1
更好的解决方案是使用带有MaskFormatter的JFormattedTextField。MaskFormatter mask = new MaskFormatter("*****");JFormattedTextField textField = new JFormattedTextField(mask) - Ould Abba
显示剩余2条评论

25
自从Java 1.4引入了DocumentFilter以来,覆盖重写Document的需求已经减少。 DocumentFilter提供了在内容传递到Document之前对其进行过滤的手段。
这使得字段可以继续保持它所需的任何文档,同时提供了过滤用户输入的方法。
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

public class LimitTextField {

    public static void main(String[] args) {
        new LimitTextField();
    }

    public LimitTextField() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JTextField pfPassword = new JTextField(20);
                ((AbstractDocument)pfPassword.getDocument()).setDocumentFilter(new LimitDocumentFilter(15));

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridBagLayout());
                frame.add(pfPassword);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class LimitDocumentFilter extends DocumentFilter {

        private int limit;

        public LimitDocumentFilter(int limit) {
            if (limit <= 0) {
                throw new IllegalArgumentException("Limit can not be <= 0");
            }
            this.limit = limit;
        }

        @Override
        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
            int currentLength = fb.getDocument().getLength();
            int overLimit = (currentLength + text.length()) - limit - length;
            if (overLimit > 0) {
                text = text.substring(0, text.length() - overLimit);
            }
            if (text.length() > 0) {
                super.replace(fb, offset, length, text, attrs); 
            }
        }

    }

}

为什么要覆盖 replace 而不是 insertString?它是否适用于插入和替换文本两种情况? - Gustavo
@Gustavo 不是很准确,通常 replace 几乎总是被调用的,事实上,你可以只让 insertString 在少数情况下调用 replace。添加一些调试语句并查看。 - MadProgrammer
完美的例子 - Sachindra N. Pandey
4
@MadProgrammer 我遇到了同样的问题,并通过将条件替换为:text.length() > 0 || length > 0 来进行了更正。这样它就可以检查插入或删除文本(当您清除字段时会发生这种情况)。 - Bruce Feist
1
@fatih if (text.length() >= 0) 总是为真,因为字符串长度不能为负数。 - PhoneixS
显示剩余4条评论

4

很奇怪的是Swing工具包没有包含这个功能,但是这是您问题的最佳答案:

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

我在我的Udemy.com课程“像孩子一样学习Java”中使用这个有趣的猜谜游戏示例。祝好 - Bryson


2
“Swing 工具包不包含这个功能有点奇怪” - 这个功能被称为 DocumentFilter - MadProgrammer
1
我相信Payne博士的意思是,Swing没有将此功能作为JTextField的属性包含其中,这似乎是一个常见的需求。 - Mishax
2
这不会阻止粘贴超过3个字符的内容。 - felvhage

0
这里有另一种将长度限制如下的方法。
label_4_textField.addKeyListener(new KeyListener() {
            
    @Override
    public void keyTyped(KeyEvent arg0) {
        if(label_4_textField.getText().length()>=4) // Limit to 4 characters
        {
            label_4_textField.setText(label_4_textField.getText().substring(0,3));
        }
    }
});

0
private void jTextField1KeyPressed(java.awt.event.KeyEvent evt)
{
    if(jTextField1.getText().length()>=5)
    {
        jTextField1.setText(jTextField1.getText().substring(0, 4));
    }
}

我已经创建了一个名为jTextField1的JTextField,代码在它的key pressed事件中。我已经测试过它可以工作。我正在使用NetBeans IDE。


2
不 - keyListener 不是验证输入的选项(例如限制字符数) - kleopatra
为什么会有这么多的踩?我认为这是实现目标的聪明方式。+1 - h2O
4
因为这是个不好的想法。这种方法没有考虑到用户如果把文本粘贴到该字段中,可能在某些平台上得不到通知... - MadProgrammer

0

私有的 void validateInput() {

      if (filenametextfield.getText().length() <= 3 )
        {

          errorMsg2.setForeground(Color.RED);

        }
        else if(filenametextfield.getText().length() >= 3 && filenametextfield.getText().length()<= 25)
        {

             errorMsg2.setForeground(frame.getBackground());
             errorMsg.setForeground(frame2.getBackground());

        } 
        else if(filenametextfield.getText().length() >= 25)
        {

             remove(errorMsg2);
             errorMsg.setForeground(Color.RED);
             filenametextfield.addKeyListener(new KeyAdapter() {
                  public void keyTyped(KeyEvent e) {
                     if(filenametextfield.getText().length()>=25)
                        {
                         e.consume();
                         e.getModifiers();

                        }
                 }
            });
        }


    }

以上代码要求用户输入字符,长度应大于3且小于25。此外,该代码还帮助用户编辑和重新输入字符,这是大多数其他解决方案所不允许的。 - jinuprakash

-1

这是npinti答案的优化版本:

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.PlainDocument;
import java.awt.*;

public class TextComponentLimit extends PlainDocument
{
    private int charactersLimit;

    private TextComponentLimit(int charactersLimit)
    {
        this.charactersLimit = charactersLimit;
    }

    @Override
    public void insertString(int offset, String input, AttributeSet attributeSet) throws BadLocationException
    {
        if (isAllowed(input))
        {
            super.insertString(offset, input, attributeSet);
        } else
        {
            Toolkit.getDefaultToolkit().beep();
        }
    }

    private boolean isAllowed(String string)
    {
        return (getLength() + string.length()) <= charactersLimit;
    }

    public static void addTo(JTextComponent textComponent, int charactersLimit)
    {
        TextComponentLimit textFieldLimit = new TextComponentLimit(charactersLimit);
        textComponent.setDocument(textFieldLimit);
    }
}

如果要为您的JTextComponent添加限制,只需编写以下代码行:

JTextFieldLimit.addTo(myTextField, myMaximumLength);

-1
public void Letters(JTextField a) {
    a.addKeyListener(new KeyAdapter() {
        @Override
        public void keyTyped(java.awt.event.KeyEvent e) {
            char c = e.getKeyChar();
            if (Character.isDigit(c)) {
                e.consume();
            }
            if (Character.isLetter(c)) {
                e.setKeyChar(Character.toUpperCase(c));
            }
        }
    });
}

public void Numbers(JTextField a) {
    a.addKeyListener(new KeyAdapter() {
        @Override
        public void keyTyped(java.awt.event.KeyEvent e) {
            char c = e.getKeyChar();
            if (!Character.isDigit(c)) {
                e.consume();
            }
        }
    });
}

public void Caracters(final JTextField a, final int lim) {
    a.addKeyListener(new KeyAdapter() {
        @Override
        public void keyTyped(java.awt.event.KeyEvent ke) {
            if (a.getText().length() == lim) {
                ke.consume();
            }
        }
    });
}

如果用户将长字符串复制并粘贴到文本字段中,则此方法将无效。 - Matthew Wise

-1

private void jTextField1KeyTyped(java.awt.event.KeyEvent evt) {                                   
if (jTextField1.getText().length()>=3) {
            getToolkit().beep();
            evt.consume();
        }
    }


3
除了提供代码,附加解释可以帮助说明你的答案。为了使你的答案更加易懂,建议在代码旁边加上解释。 - SteveFerg

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