【问题标题】:JTextField limiting character amount input and accepting numeric onlyJTextField 限制字符量输入并仅接受数字
【发布时间】:2012-09-29 08:54:21
【问题描述】:

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

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

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

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

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

}

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

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

【问题讨论】:

  • 只是一个注释。您可以跳过if 代码中的== true 部分,它们是多余的。此外,如果需要,== false 可以在表达式前替换为 !
  • 我做了一个 textfieldKeytyped 和 evt.consume 来限制字符和一个文档过滤器来接受字母或数字。
  • 这个博客有一个类似的帖子可以满足你的需要:theunixshell.blogspot.com/search/label/java

标签: java swing jtextfield documentfilter


【解决方案1】:
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);
            }
        }
    }
}

【讨论】:

  • @Irfan 没有人问...?
  • 问题是如何限制 jtextfield 长度并同时只接受数字?我的组件只接受数字(initializeForNumbers()),长度受构造函数限制......
【解决方案2】:

我目前正在使用数独求解器进行一个小项目。通过检查输入是否在带有数字的字符串数组中,我将输入限制为仅数字。我直接写在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);
                }
            }
        }
    }
}

【讨论】:

    【解决方案3】:
    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;
    
    }
    

    【讨论】:

      【解决方案4】:
          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  
                        }
                    }   
              });
           }  
         }
      

      【讨论】:

        【解决方案5】:
        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
                        }
                    }
                })
        

        【讨论】:

        • 永远不要为 JTextComponents 使用 KeyListener,与 Document 相比,您可以监听减少的事件,从从 ClipBouar 插入的字符串/字符开始(复制 -> 粘贴)等。
        【解决方案6】:

        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 将被调用

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

        (oldValue 或 newValue 在 "" 文本大小写中将为空)

        每次有效编辑后

        【讨论】:

          【解决方案7】:

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

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

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

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

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

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

          更新

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

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

          ChainableFilter chainableFilter = new ChainableFilter();
          chainableFilter.addFilter(new RestrictedLengthFilter()); // User supplied filter 
          chainableFilter.addFilter(new NumericFilter()); // User supplied filter 
          
          ((AbstractDocument)textField.getDocument()).setDocumentFilter(chainableFilter);
          

          至于实际的过滤器,我会查看我之前发布的链接。不过,您的想法正走在正确的轨道上

          更新

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

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

          【讨论】:

          • 好的,我创建了一个新的 .java 类并将其命名为 ChanableFilter。我粘贴了你的代码并得到了错误。我导入了所需的导入并使用了一些尝试捕获方法来修复错误我仍然得到三个错误
          • public void void remove(DocumentFilter.FilterBypass fb, int offset, int length) { "非法的表达式开头,'('预期
          • 抱歉,Weddy,我从内存中一瘸一拐地把代码拼凑在一起。我已经更正了它并确保它可以编译。检查更新
          • 我放了一个完整的例子,老实说,MDP 的 WebLog 中的数字过滤器比我从您的代码转换的那个要好得多...
          • 嗯,这种方法真的有效吗?在我看来,文档将被更新两次。数字编辑成功一次,大小编辑成功一次。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-10-14
          • 2013-01-14
          • 1970-01-01
          • 2014-01-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多