将 JTextField 输入限制为整数 [duplicate]

Restricting JTextField input to Integers [duplicate]

提问人:AndroidDev 提问时间:6/19/2012 最后编辑:JimmyPenaAndroidDev 更新时间:6/9/2016 访问量:282049

问:

我知道这个问题一定被问过和回答过一百万次,但我就是找不到一个简单的解决方案。我有一个 JTextField,它只接受正整数作为输入。我需要一种方法来确保这里没有其他输入。

我已经将一个 keyListener 附加到此控件。删除此侦听器要处理的其他代码,我有这个:

       txtAnswer.addKeyListener(new KeyAdapter() {
        @Override
        public void keyPressed(KeyEvent e) {

            int key = e.getKeyCode();

            /* Restrict input to only integers */
            if (key < 96 && key > 105) e.setKeyChar('');
        };
    });

如您所见,我正在尝试使用 KeyCode 来检查刚刚按下的键是否落在整数范围内。这似乎有效。但我想做的是,如果条目超出此范围,请简单地忽略它。该代码旨在处理此问题,但它不起作用。代码将编译,但没有可见的效果。e.setKeyChar('')

谁能告诉我我是否走在正确的轨道上?我可以用什么来代替它?还是我完全走错了方向?e.setKeyChar('')

谢谢。

Java 摆动 数字 jtextfield

评论

0赞 nIcE cOw 6/19/2012
@Randy : 请也看看这个例子

答:

77赞 Hovercraft Full Of Eels 6/19/2012 #1

不要为此使用 KeyListener,因为您会错过很多东西,包括粘贴文本。此外,KeyListener 是一个非常低级的构造,因此在 Swing 应用程序中应避免使用。

该解决方案已在 SO 上多次描述:使用 DocumentFilter。这个网站上有几个这样的例子,有些是我写的。

例如:using-documentfilter-filterbypass

另有关教程帮助,请查看:实现 DocumentFilter

编辑

例如:

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
import javax.swing.text.PlainDocument;

public class DocFilter {
   public static void main(String[] args) {
      JTextField textField = new JTextField(10);

      JPanel panel = new JPanel();
      panel.add(textField);

      PlainDocument doc = (PlainDocument) textField.getDocument();
      doc.setDocumentFilter(new MyIntFilter());


      JOptionPane.showMessageDialog(null, panel);
   }
}

class MyIntFilter extends DocumentFilter {
   @Override
   public void insertString(FilterBypass fb, int offset, String string,
         AttributeSet attr) throws BadLocationException {

      Document doc = fb.getDocument();
      StringBuilder sb = new StringBuilder();
      sb.append(doc.getText(0, doc.getLength()));
      sb.insert(offset, string);

      if (test(sb.toString())) {
         super.insertString(fb, offset, string, attr);
      } else {
         // warn the user and don't allow the insert
      }
   }

   private boolean test(String text) {
      try {
         Integer.parseInt(text);
         return true;
      } catch (NumberFormatException e) {
         return false;
      }
   }

   @Override
   public void replace(FilterBypass fb, int offset, int length, String text,
         AttributeSet attrs) throws BadLocationException {

      Document doc = fb.getDocument();
      StringBuilder sb = new StringBuilder();
      sb.append(doc.getText(0, doc.getLength()));
      sb.replace(offset, offset + length, text);

      if (test(sb.toString())) {
         super.replace(fb, offset, length, text, attrs);
      } else {
         // warn the user and don't allow the insert
      }

   }

   @Override
   public void remove(FilterBypass fb, int offset, int length)
         throws BadLocationException {
      Document doc = fb.getDocument();
      StringBuilder sb = new StringBuilder();
      sb.append(doc.getText(0, doc.getLength()));
      sb.delete(offset, offset + length);

      if (test(sb.toString())) {
         super.remove(fb, offset, length);
      } else {
         // warn the user and don't allow the insert
      }

   }
}

为什么这很重要?

  • 如果用户使用复制和粘贴将数据插入到文本组件中,该怎么办?KeyListener 会错过这个吗?
  • 您似乎希望检查数据是否可以表示 int。如果他们输入的数值数据不合适怎么办?
  • 如果要允许用户稍后输入双重数据,该怎么办?在科学记数法中?

评论

1赞 trashgod 6/19/2012
+1 同时考虑 InputVerifier
0赞 AndroidDev 6/20/2012
这很酷。我已经盯着看了很长一段时间了,并在一个简化的应用程序中测试了它。我或多或少了解它的作用以及原因(或多或少!不过,这给我带来了一个问题。在我的 JTextBox 上,在用户按下回车键后,我调用了一些方法,我仍然使用 KeyListener 来完成这些方法。这似乎有效。但是我需要对这个文本框做的最后一件事是清除它,以便可以输入新文本。我是用txtAnswer.setText(“”);但现在看来,此文档过滤器阻止了此操作。谁能建议?谢谢
1赞 Hovercraft Full Of Eels 6/20/2012
@Randy:更改 test(String text) 方法。如果为 true,则让它返回 true。text.trim().isEmpty()
0赞 user1296058 2/15/2014
感谢您的样品。这非常有用。您的示例似乎将输入限制为最多 10 位数字。你能告诉我如何增加这个吗?
5赞 BaptisteL 2/21/2017
我遇到了无法擦除最后一位数字的问题,如果您有同样的问题,则可以在删除函数中使用这段代码。 在我的示例中,我将其替换为 ,但您可以将其替换为if(sb.toString().length() == 0) { super.replace(fb, offset, length, "0", null); } else { if (test(sb.toString())) { super.remove(fb, offset, length); } else { // warn the user and don't allow the insert } }"0"""
22赞 paulsm4 6/19/2012 #2

下面是一种使用 keylistener 但使用 keyChar(而不是 keyCode)的方法:

http://edenti.deis.unibo.it/utils/Java-tips/Validating%20numerical%20input%20in%20a%20JTextField.txt

 keyText.addKeyListener(new KeyAdapter() {
    public void keyTyped(KeyEvent e) {
      char c = e.getKeyChar();
      if (!((c >= '0') && (c <= '9') ||
         (c == KeyEvent.VK_BACK_SPACE) ||
         (c == KeyEvent.VK_DELETE))) {
        getToolkit().beep();
        e.consume();
      }
    }
  });

另一种方法(我个人认为它几乎和 Swing 的 JTree 模型一样过于复杂)是使用格式化文本字段:

http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html

评论

0赞 Markus Duft 4/28/2023
如果您想使用 JTextField,这是迄今为止最简单、最有用的方法
6赞 Chan 6/19/2012 #3

我曾经使用过 Key Listener,但这种方法失败了很长时间。如前所述,最佳方法是使用 DocumentFilter。下面是我创建的一个实用方法,用于仅使用数字输入构建文本字段。请注意,它也将采用单个“.”字符,因为它可用于十进制输入。

public static void installNumberCharacters(AbstractDocument document) {
        document.setDocumentFilter(new DocumentFilter() {
            @Override
            public void insertString(FilterBypass fb, int offset,
                    String string, AttributeSet attr)
                    throws BadLocationException {
                try {
                    if (string.equals(".")
                            && !fb.getDocument()
                                    .getText(0, fb.getDocument().getLength())
                                    .contains(".")) {
                        super.insertString(fb, offset, string, attr);
                        return;
                    }
                    Double.parseDouble(string);
                    super.insertString(fb, offset, string, attr);
                } catch (Exception e) {
                    Toolkit.getDefaultToolkit().beep();
                }

            }

            @Override
            public void replace(FilterBypass fb, int offset, int length,
                    String text, AttributeSet attrs)
                    throws BadLocationException {
                try {
                    if (text.equals(".")
                            && !fb.getDocument()
                                    .getText(0, fb.getDocument().getLength())
                                    .contains(".")) {
                        super.insertString(fb, offset, text, attrs);
                        return;
                    }
                    Double.parseDouble(text);
                    super.replace(fb, offset, length, text, attrs);
                } catch (Exception e) {
                    Toolkit.getDefaultToolkit().beep();
                }
            }
        });
    }
57赞 Peter Tseng 4/26/2013 #4

您也可以使用 ,使用起来要简单得多。例:JFormattedTextField

public static void main(String[] args) {
    NumberFormat format = NumberFormat.getInstance();
    NumberFormatter formatter = new NumberFormatter(format);
    formatter.setValueClass(Integer.class);
    formatter.setMinimum(0);
    formatter.setMaximum(Integer.MAX_VALUE);
    formatter.setAllowsInvalid(false);
    // If you want the value to be committed on each keystroke instead of focus lost
    formatter.setCommitsOnValidEdit(true);
    JFormattedTextField field = new JFormattedTextField(formatter);

    JOptionPane.showMessageDialog(null, field);

    // getValue() always returns something valid
    System.out.println(field.getValue());
}

评论

4赞 12/20/2013
有了这个,用户可以在字段中插入字母。
5赞 cesAR 10/3/2016
这种方法效果很好,除了一件事:一旦你输入了一个数字,第一个数字就不能用Backspace键删除。
0赞 BaptisteL 2/21/2017
@cesAR : 我通过编码自己的实现来修复它,您可以参考气垫船充满鳗鱼的答案,我还在最后添加了一条评论来解决这个问题。问题来自这样一个事实,即它不被视为有效的 Interger/Double ..""
0赞 Halfacht 10/9/2017
field.setColumns(..) //对于宽度大于 1000 的数字,不能解析为整数。(通常的方式)
0赞 Stevey 11/19/2020
我尝试了这种方法,但需要 minimum=100 和 maximum=300,并且设置这些设置根本无法编辑该字段,因为无法在不使文本无效的情况下修改文本。我进入了后处理阶段,我检查值并在超出范围时发牢骚。
23赞 Umi 6/18/2013 #5

我简直不敢相信我还没有在堆栈溢出的任何地方找到这个简单的解决方案,它是迄今为止最有用的。更改 Document 或 DocumentFilter 不适用于 JFormattedTextField。Peter Tseng的回答非常接近。

NumberFormat longFormat = NumberFormat.getIntegerInstance();

NumberFormatter numberFormatter = new NumberFormatter(longFormat);
numberFormatter.setValueClass(Long.class); //optional, ensures you will always get a long value
numberFormatter.setAllowsInvalid(false); //this is the key!!
numberFormatter.setMinimum(0l); //Optional

JFormattedTextField field = new JFormattedTextField(numberFormatter);

评论

10赞 LeeCambl 11/14/2014
在您开始在其中输入内容后,该字段也永远不会为空(即,如果我键入 1234 并决定“实际上,我不想在此字段中使用数字”,则至少会保留 1 个字符)。
6赞 Enwired 1/27/2017
@LeeCambl 可以通过创建一个子类来解决这个问题,该子类的子类将覆盖以返回空字符串。NumberFormatterstringToValue(String text)null
3赞 user3498019 5/5/2014 #6

当您在密钥释放后向 JtextField1 键入整数时,它将转到 inside try ,对于任何其他字符,它将抛出 NumberFormatException。如果在捕获中将空字符串设置为 jTextField1,则用户无法键入除正数之外的任何其他键,因为每次错误尝试都会清除 JTextField1。

 //Fields 
int x;
JTextField jTextField1;

 //Gui Code Here

private void jTextField1KeyReleased(java.awt.event.KeyEvent evt) {                                        
    try {
        x = Integer.parseInt(jTextField1.getText());
    } catch (NumberFormatException nfe) {
        jTextField1.setText("");
    }
}