2012-06-19 43 views
31

Tôi biết rằng câu hỏi này phải được hỏi và trả lời hàng triệu lần, nhưng tôi không thể tìm được giải pháp dễ dàng. Tôi có một JTextField đó là có nghĩa là để chấp nhận chỉ số nguyên dương như đầu vào. Tôi cần một cách để đảm bảo rằng không có gì khác được nhập vào đây.Hạn chế nhập JTextField thành Số nguyên

Tôi đã có một trình keyListener gắn với điều khiển này. Xóa mã khác mà nghe này là có để xử lý, tôi có điều này:

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

Như bạn thấy, tôi đang cố gắng sử dụng các mã phím để kiểm tra xem phím vừa nhấn thác trong phạm vi của số nguyên . Điều này dường như hoạt động. Nhưng những gì tôi muốn làm là chỉ đơn giản là bỏ qua mục nhập nếu nó nằm ngoài phạm vi này. Mã e.setKeyChar('') có nghĩa là để xử lý việc này, nhưng nó không hoạt động. Mã sẽ biên dịch, nhưng nó không có hiệu lực nhìn thấy được.

Ai có thể cho tôi biết nếu tôi đi đúng hướng không? Tôi có thể thay thế e.setKeyChar('') bằng cách nào để thực hiện công việc này? Hay tôi hoàn toàn đi sai hướng?

Cảm ơn.

+0

@Randy: Xin đừng nhìn vào này [ví dụ] (http://stackoverflow.com/questions/9477354/how-to-allow-introducing-only-digits-in-jtextfield/9478124#9478124) cũng –

+0

http://theunixshell.blogspot.com/search/label/java – Vijay

Trả lời

54

Không sử dụng KeyListener cho điều này vì bạn sẽ bỏ lỡ nhiều việc bao gồm dán văn bản. Ngoài ra một KeyListener là một cấu trúc rất thấp và như vậy, nên tránh trong các ứng dụng Swing.

Giải pháp đã được mô tả nhiều lần trên SO: Sử dụng DocumentFilter. Có một số ví dụ về điều này trên trang web này, một số được viết bởi tôi.

Ví dụ: using-documentfilter-filterbypass

Cũng cho hướng dẫn giúp đỡ, xin vui lòng xem xét: Implementing a DocumentFilter.

Sửa

Ví dụ:

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 
     } 

    } 
} 

Tại sao điều này lại quan trọng?

  • Điều gì xảy ra nếu người dùng sử dụng sao chép và dán để chèn dữ liệu vào thành phần văn bản? Một KeyListener có thể bỏ lỡ điều này?
  • Dường như bạn muốn kiểm tra xem dữ liệu có thể đại diện cho int hay không. Điều gì xảy ra nếu họ nhập dữ liệu số không phù hợp?
  • Điều gì xảy ra nếu bạn muốn cho phép người dùng sau này nhập dữ liệu kép? Trong ký hiệu khoa học?
+1

+1 Cũng xem xét ['InputVerifier'] (http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html# inputVerification). – trashgod

+1

+ !, cách tiếp cận này đơn giản hơn nhiều, không nghi ngờ gì, vì nhiều người liên quan đến BackSpace, Delete, Excape, Home, Insert blah blah 'Key Events' không làm phiền bạn với' DocumentFilter'. –

+0

Cảm ơn bạn đã đề xuất! Tôi sẽ phải làm một số đọc về bộ lọc tài liệu. Chúng không trực quan đối với tôi với tư cách là người nghe chính, nhưng có vẻ như nó đáng để bắt kịp tốc độ. Cảm ơn một lần nữa. – Alex

11

Dưới đây là một cách tiếp cận có sử dụng một keylistener, nhưng sử dụng các keyChar (thay vì 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(); 
     } 
    } 
    }); 

cách tiếp cận khác (mà cá nhân tôi thấy gần như là quá phức tạp như Mô hình JTree của Swing) là sử dụng Trường văn bản được định dạng:

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

+1

@Randy: xin lỗi, nhưng đây là cách tiếp cận hoàn toàn sai. Một lần nữa, bạn không nên sử dụng một KeyListener cho việc này. Giai đoạn. –

+1

@Randy: Không quan trọng là bạn đã chấp nhận câu trả lời này. Chờ đã, hãy để tôi chỉ ra cách tiếp cận chính xác, bởi vì điều này làm tôi khó chịu. –

+2

Có một FormattedTextField là một giải pháp phức tạp hơn câu trả lời của bạn, nhưng đó là một giải pháp tốt hơn nhiều. Xin lỗi, nhưng giải pháp của bạn nhắc tôi về báo giá H.L. Mencken, “Đối với mọi vấn đề có một giải pháp đơn giản, sạch sẽ và sai.” –

5

Tôi đã từng sử dụng Trình nghe khóa cho điều này nhưng tôi đã thất bại trong thời gian dài với cách tiếp cận đó. Cách tiếp cận tốt nhất như được khuyến nghị là sử dụng DocumentFilter.Dưới đây là một phương thức tiện ích mà tôi đã tạo để xây dựng các trường văn bản chỉ với số đầu vào. Chỉ cần cẩn thận rằng nó cũng sẽ mất duy nhất '.' nhân vật cũng vì nó có thể sử dụng cho đầu vào thập phân.

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

Bạn cũng có thể sử dụng JFormattedTextField, đơn giản hơn nhiều để sử dụng. Ví dụ:

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

Với điều này, người dùng có thể chèn chữ vào trường. –

+0

@ Peter Tseng. mã của bạn cần phải thêm formatter.setAllowsInvalid (false); để được OK. – dervish

+0

@dervish Cảm ơn! –

17

Tôi không thể tin rằng mình chưa tìm thấy giải pháp đơn giản này ở bất kỳ đâu trên ngăn xếp ngăn xếp, nó là hữu ích nhất. Thay đổi Document hoặc DocumentFilter không hoạt động với JFormattedTextField. Câu trả lời của Peter Tseng rất gần.

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

Trường này cũng không bao giờ trống sau khi bạn bắt đầu nhập nội dung nào đó (ví dụ: nếu tôi nhập 1234 và quyết định "thực sự, tôi không muốn một số trong trường này", ít nhất 1 ký tự sẽ vẫn còn). – LeeCambl

+2

@LeeCambl Có thể giải quyết vấn đề đó bằng cách tạo một lớp con của 'NumberFormatter' ghi đè' stringToValue (chuỗi văn bản) 'để trả về' null' cho một chuỗi rỗng. – Enwired

3

Khi bạn nhập số nguyên vào JtextField1 sau khi phát hành chính nó sẽ đi vào bên trong thử, đối với bất kỳ ký tự nào khác, nó sẽ ném NumberFormatException. Nếu bạn đặt chuỗi rỗng thành jTextField1 bên trong phần đánh bắt để người dùng không thể nhập bất kỳ khóa nào khác ngoại trừ số dương vì JTextField1 sẽ bị xóa cho mỗi lần thử xấu.

//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(""); 
    } 
} 
Các vấn đề liên quan