java JTextField 限制字符数量输入并仅接受数字

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12793030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 10:14:40  来源:igfitidea点击:

JTextField limiting character amount input and accepting numeric only

javaswingjtextfielddocumentfilter

提问by Weddy

here's the code that i have on how to limit the character input length

这是我关于如何限制字符输入长度的代码

class JTextFieldLimit extends PlainDocument {
  private int limit;
  // optional uppercase conversion
  private boolean toUppercase = false;

  JTextFieldLimit(int limit) {
   super();
   this.limit = limit;
   }

  JTextFieldLimit(int limit, boolean upper) {
   super();
   this.limit = limit;
   toUppercase = upper;
   }

    @Override
  public void insertString
    (int offset, String  str, AttributeSet attr)
      throws BadLocationException {
   if (str == null) return;

   if ((getLength() + str.length()) <= limit) {
     if (toUppercase) str = str.toUpperCase();
     super.insertString(offset, str, attr);
     }
   }
}

can be implemented by txtSample.setDocument(new JTextFieldLimit(30));

可以通过 txtSample.setDocument(new JTextFieldLimit(30));

and here's what i have on accepting numeric numbers only(it accepts decimal though w/c i dont need)

这是我只接受数字的内容(它接受十进制,尽管 w/ci 不需要)

class NumericDocument extends PlainDocument {

     protected int decimalPrecision = 0;
     protected boolean allowNegative = false;


     public NumericDocument(int decimalPrecision, boolean allowNegative) {
          super();
          this.decimalPrecision = decimalPrecision;
          this.allowNegative = allowNegative;
     }



    @Override
     public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException {
          if (str != null){
               if (StringFormat.isNumeric(str) == false && str.equals(".") == false && str.equals("-") == false){ //First, is it a valid character?
                    Toolkit.getDefaultToolkit().beep();
                    return;
               }
               else if (str.equals(".") == true && super.getText(0, super.getLength()).contains(".") == true){ //Next, can we place a decimal here?
                    Toolkit.getDefaultToolkit().beep();
                    return;
               }
               else if (StringFormat.isNumeric(str) == true && super.getText(0, super.getLength()).indexOf(",") != -1 && offset>super.getText(0, super.getLength()).indexOf(",") && super.getLength()-super.getText(0, super.getLength()).indexOf(".")>decimalPrecision && decimalPrecision > 0){ //Next, do we get past the decimal precision limit?
                    Toolkit.getDefaultToolkit().beep();
                    return;
               }
               else if (str.equals("-") == true && (offset != 0 || allowNegative == false)){ //Next, can we put a negative sign?
                    Toolkit.getDefaultToolkit().beep();
                    return;
               }


               super.insertString(offset, str, attr);
          }
          return;
     }
public static class StringFormat
{
    public StringFormat()
    {
    }
    public static boolean isNumeric(String str)
    {
        try
        {
            int x = Integer.parseInt(str);
            System.out.println(x); return true;
        } catch(NumberFormatException nFE)
        {
            System.out.println("Not an Integer"); return false;
        }
    }
}

}

and heres how to use this code: txtSample.setDocument(new NumericDocument(0,false));

以及如何使用此代码: txtSample.setDocument(new NumericDocument(0,false));

now the problem is the txtSamplecan only setDocumentonce. How do i limit a jtextfield length and accept numbers only at the same time? Or is there any simpler way to do this? Thanks. :D

现在的问题是txtSample只能setDocument一次。如何限制 jtextfield 长度并同时仅接受数字?或者有没有更简单的方法来做到这一点?谢谢。:D

回答by MadProgrammer

You're on the right track, except you will want to use a DocumentFilterinstead of implementing your own document.

您走在正确的轨道上,除了您想要使用DocumentFilter而不是实现您自己的文档。

MDP's Webloghas a number of excellent examples (including limiting the length and character type).

MDP 的 Weblog有很多很好的例子(包括限制长度和字符类型)。

Now to the your question, you could create cascading filter, where you could chain a series of filters together.

现在回答您的问题,您可以创建级联过滤器,您可以在其中将一系列过滤器链接在一起。

This would allow you to call each filter in turn.

这将允许您依次调用每个过滤器。

public class ChainableFilter extends DocumentFilter {

    private List<DocumentFilter> filters;
    private AttributeSet attr;

    public ChainableFilter() {
        filters = new ArrayList<DocumentFilter>(25);
    }

    public void addFilter(DocumentFilter filter) {
        filters.add(filter);
    }

    public void removeFilter(DocumentFilter filter) {
        filters.remove(filter);
    }

    public void insertString(DocumentFilter.FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
        for (DocumentFilter filter : filters) {
            filter.insertString(fb, offset, string, attr);
        }
    }        

    public void remove(DocumentFilter.FilterBypass fb, int offset, int length) throws BadLocationException {
        for (DocumentFilter filter : filters) {
            filter.remove(fb, offset, length);
        }
    }

    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
        for (DocumentFilter filter : filters) {
            filter.replace(fb, offset, length, text, attrs);
        }
    }

}

Now it would be nice if filter could actually tell the chain if it altered the document at all, but I'll leave that up to you

现在,如果过滤器实际上可以告诉链是否改变了文档,那就太好了,但我会把它留给你

UPDATED

更新

The basic concept between what you've done and how DocumentFilterswork is pretty much the same. The benefit is, you're not limiting your self to a PlainDocument, you could, in theory, apply it to a JTextPaneor JEditorPane.

您所做的工作与DocumentFilters工作方式之间的基本概念几乎相同。好处是,您不会将自己限制在 a 上PlainDocument,理论上您可以将其应用于 aJTextPaneJEditorPane

The basic idea of the filter chain is simple.

过滤器链的基本思想很简单。

ChainableFilter chainableFilter = new ChainableFilter();
chainableFilter.addFilter(new RestrictedLengthFilter()); // User supplied filter 
chainableFilter.addFilter(new NumericFilter()); // User supplied filter 

((AbstractDocument)textField.getDocument()).setDocumentFilter(chainableFilter);

As for the actual filters, I'd check out the link I posted earlier. You're on the right track with your ideas though

至于实际的过滤器,我会查看我之前发布的链接。虽然你的想法是正确的

UPDATED

更新

SizeFilter sizeFilter = new SizeFilter(12);
NumberFilter numFilter = new NumberFilter();
ChainableFilter chainFilter = new ChainableFilter();
chainFilter.addFilter(sizeFilter);
chainFilter.addFilter(numFilter);

JTextField field = new JTextField();
((AbstractDocument) field.getDocument()).setDocumentFilter(chainFilter);



    public class NumberFilter extends DocumentFilter {

        private int decimalPrecision = 2;
        private boolean allowNegative = false;

        public NumberFilter() {
        }

        public NumberFilter(int decimals, boolean negatives) {
            decimalPrecision = decimals;
            allowNegative = negatives;
        }

        protected boolean accept(FilterBypass fb, int offset, String str) throws BadLocationException {
            boolean accept = true;    
            int length = fb.getDocument().getLength();
            String currentText = fb.getDocument().getText(0, length);

            if (str != null) {
                if (!isNumeric(str) && !str.equals(".") && !str.equals("-")) { //First, is it a valid character?
                    Toolkit.getDefaultToolkit().beep();
                    accept = false;
                } else if (str.equals(".") && currentText.contains(".")) { //Next, can we place a decimal here?
                    Toolkit.getDefaultToolkit().beep();
                    accept = false;
                } else if (isNumeric(str)
                                && currentText.indexOf(",") != -1
                                && offset > currentText.indexOf(",")
                                && length - currentText.indexOf(".") > decimalPrecision
                                && decimalPrecision > 0) { //Next, do we get past the decimal precision limit?
                    Toolkit.getDefaultToolkit().beep();
                    accept = false;
                } else if (str.equals("-") && (offset != 0 || !allowNegative)) { //Next, can we put a negative sign?
                    Toolkit.getDefaultToolkit().beep();
                    accept = false;
                }
            }
            return accept;
        }

        @Override
        public void insertString(FilterBypass fb, int offset, String str, AttributeSet as) throws BadLocationException {
            if (accept(fb, offset, str)) {
                super.insertString(fb, offset, str, as);
            }
        }

        @Override
        public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
            if (accept(fb, offset, text)) {
                super.replace(fb, offset, length, text, attrs);
            }
        }

        public boolean isNumeric(String str) {
            try {
                int x = Integer.parseInt(str);
                System.out.println(x);
                return true;
            } catch (NumberFormatException nFE) {
                System.out.println("Not an Integer");
                return false;
            }
        }
    }

    public class SizeFilter extends DocumentFilter {

        private int maxCharacters;

        public SizeFilter(int maxChars) {
            maxCharacters = maxChars;
        }

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

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

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

            if ((fb.getDocument().getLength() + str.length()
                     - length) <= maxCharacters) {
                super.replace(fb, offs, length, str, a);
            } else {
                Toolkit.getDefaultToolkit().beep();
            }
        }
    }

Again, I know it compiles, but I've not tested it (the numeric filter in particular), but that would be a good exercise in debugging ;)

同样,我知道它可以编译,但我没有测试过它(特别是数字过滤器),但这将是一个很好的调试练习;)

回答by gmatagmis

JFormattedTextField

JFormattedTextField

 JTextComponent txt = new JFormattedTextField( new LimitedIntegerFormatter(limit) );
  txt.addPropertyChangeListener("value", yourPropertyChangeListener);


import javax.swing.text.DefaultFormatter;
import java.text.ParseException;

public class LimitedIntegerFormatter extends DefaultFormatter {

  static final long serialVersionUID = 1l;
  private int limit;

  public LimitedIntegerFormatter( int limit ) {
    this.limit = limit;
    setValueClass(Integer.class);
    setAllowsInvalid(false);
    setCommitsOnValidEdit(true);
  }
  @Override
  public Object stringToValue(String string) throws ParseException {
    if (string.equals("")) return null;
    if (string.length() > limit) throw new ParseException(string, limit);
    return super.stringToValue(string);
  }
}

yourPropertyChangeListener will be called with

yourPropertyChangeListener 将被调用

new PropertyChangeEvent( "value", Integer oldValue, Integer newValue )

new PropertyChangeEvent( "value", Integer oldValue, Integer newValue )

( oldValue or newValue will be null in "" text case )

( oldValue 或 newValue 在 "" 文本情况下将为 null )

after every valid edit

每次有效编辑后

回答by pixylife

    import java.awt.event.KeyAdapter;    
    import java.awt.event.KeyEvent;    
    import javax.swing.JTextField;        

    public class Validation {

         public static void validateInt(final JTextField txt){
            txt.addKeyListener(new KeyAdapter() {

                   @Override
                   public void keyTyped(KeyEvent e) {
                        char c = e.getKeyChar();
                        if ( ((c < '0') || (c > '9')) 
                             && (c != KeyEvent.VK_BACK_SPACE)) {
                        e.consume();  // ignore event
                   }
               }
            });
        }

        public static void validatelength(final JTextField txt,final int size){    
              txt.addKeyListener(new KeyAdapter() {

              @Override 
              public void keyTyped(KeyEvent e) {     
                  String text = txt.getText();  
                  int length = text.length();  
                  if (length == size) {  
                          e.consume();// ignore event  
                  }
              }   
        });
     }  
   }

回答by pixylife

public static boolean validateInt(String txt) {

    String regx = "^[(0-9),;]+$";
    Pattern pattern = Pattern.compile(regx, Pattern.CASE_INSENSITIVE);
    Matcher matcher = pattern.matcher(txt);
    boolean b = matcher.find();
    return b;

}

回答by Tommy Olsen

I'm currently working on a small project with a Sudoku-solver. I limited my inputs to only numbers by checking wether the input was in an string array with the numbers. I wrote it directly in the JTextFieldLimit.

我目前正在使用数独求解器进行一个小项目。我通过检查输入是否在带有数字的字符串数组中,将我的输入限制为仅数字。我直接在 JTextFieldLimit 中写的。

class JTextFieldLimit extends PlainDocument {

    private int limit;

    //Added the following 2 lines
    String[] numbers = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
    boolean isAccepted = false;
    //

    JTextFieldLimit(int limit) {
        super();
        this.limit = limit;
    }

    public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException {
        if (str == null)
            return;

        //And the following 2 lines
        for (String thisnumber : numbers) {
            isAccepted = str.equals(thisnumber);
            if (isAccepted) {
                //
                if ((getLength() + str.length()) <= limit) {
                    super.insertString(offset, str, attr);
                }
            }
        }
    }
}

回答by Igor Vukovi?

import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
import javax.swing.text.JTextComponent;
import org.apache.commons.lang.StringUtils;

public class NumberTextField extends JTextField {

    protected int maxlength = 0;

    public NumberTextField() {
        this(10);
    }

    public NumberTextField(int length) {
        super();
        this.maxlength = length;
        initializeForNumbers();
    }

    public void setMaxLength(int length) {
        this.maxlength = length;
    }

    protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
        int keyCode = e.getKeyCode();
        if (keyCode == KeyEvent.VK_ENTER || keyCode == KeyEvent.VK_ESCAPE) {
            return false;
        }
        return super.processKeyBinding(ks, e, condition, pressed);
    }

    private void initializeForNumbers() {
        Document document = getDocument();
        if (document != null) {
            ((AbstractDocument) document).setDocumentFilter(new DocumentHandler());
        }
    }

    private class DocumentHandler extends DocumentFilter {

        public void insertString(DocumentFilter.FilterBypass fb,
                int offset, String string, AttributeSet attr)
                throws BadLocationException {
            if (string == null) {
                return;
            } else {
                replace(fb, offset, 0, string, attr);
            }

        }

        public void remove(DocumentFilter.FilterBypass fb,
                int offset, int length)
                throws BadLocationException {

            replace(fb, offset, length, "", null);
        }

        public void replace(final DocumentFilter.FilterBypass fb,
                int offset, int length, String text, AttributeSet attrs)
                throws BadLocationException {

            Document doc = fb.getDocument();
            int currentLength = doc.getLength();
            String currentContent = doc.getText(0, currentLength);
            String before = currentContent.substring(0, offset);
            String after = currentContent.substring(length + offset, currentLength);
            String newValue = before + (text == null ? "" : text) + after;
            if (newValue.length() > maxlength) {
                return;
            } else {
                checkInput(newValue, offset);
                fb.replace(offset, length, text, attrs);

                if (doc.getLength() >= maxlength) {
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
                            if (c != null && c instanceof JTextComponent) {
                                JTextComponent component = (JTextComponent) c;
                                Document compDoc = component.getDocument();
                                if (compDoc.equals(fb.getDocument())) {
                                    KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
                                }
                            }
                        }
                    });
                    return;
                }
            }
        }

        private void checkInput(String proposedValue, int offset)
                throws BadLocationException {
            if (proposedValue.length() > 0 && !StringUtils.isNumeric(proposedValue)) {
                throw new BadLocationException(
                        proposedValue, offset);
            }
        }
    }
}

回答by itro

yourJTextField.addKeyListener(new KeyAdapter()
        {
            @Override
            public void keyTyped(KeyEvent e)
            {
                // Here limiting the character of your number. for examlpe this wil only accept one digit
                if (yourJTextField.getText().length() == 1) {
                    e.consume();
                }

                // Here limiting your input to only number
                char c = e.getKeyChar();
                if(!((c >= '0') && (c <= '7') || (c == KeyEvent.VK_BACK_SPACE) || (c == KeyEvent.VK_DELETE)))
                {
                    //do what so ever you want
                }
                else
                {
                    //do what so ever you want
                }
            }
        })