51

この質問は何百万回も質問され、答えられたに違いないことを私は知っていますが、私は簡単な解決策を見つけることができません。入力として正の整数のみを受け入れることを意図した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('')ますか?それとも私は完全に間違った方向に進んでいますか?

ありがとう。

4

6 に答える 6

74

これには KeyListener を使用しないでください。テキストの貼り付けなど、多くのことを見逃してしまいます。また、KeyListener は非常に低レベルの構造であるため、Swing アプリケーションでは避ける必要があります。

解決策は SO: Use a 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 を表現できることを確認したいようです。適合しない数値データを入力した場合はどうなりますか?
  • ユーザーが後で double データを入力できるようにするにはどうすればよいでしょうか。科学表記法で?
于 2012-06-19T01:47:03.943 に答える
52

を使用することもできます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());
}
于 2013-04-26T04:19:15.640 に答える
23

スタックオーバーフローのどこにもこの簡単な解決策が見つからなかったとは信じられません。これは群を抜いて最も便利です。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);
于 2013-06-18T06:24:28.283 に答える
18

キーリスナーを使用するアプローチの 1 つを次に示しますが、(keyCode の代わりに) keyChar を使用します。

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

もう 1 つのアプローチ (個人的には、Swing の JTree モデルと同じくらい複雑すぎると思います) は、書式付きテキスト フィールドを使用することです。

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

于 2012-06-19T01:49:19.443 に答える
6

私はこれにキーリスナーを使用していましたが、そのアプローチでは大失敗しました。すでに推奨されている最善のアプローチは、DocumentFilterを使用することです。以下は、数値入力のみでテキストフィールドを構築するために作成したユーティリティメソッドです。また、単一の「。」が必要になることに注意してください。10進数入力に使用できるため、文字も同様です。

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();
                }
            }
        });
    }
于 2012-06-19T02:14:44.193 に答える
4

キーを離した後に JtextField1 に整数を入力すると、内部の 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("");
    }
}   
于 2014-05-05T14:28:43.743 に答える