web-dev-qa-db-de.com

JTextField-Eingabe auf Ganzzahlen beschränken

Ich weiß, dass diese Frage eine Million Mal gestellt und beantwortet worden sein muss, aber ich kann einfach keine einfache Lösung finden. Ich habe ein JTextField, das nur positive ganze Zahlen als Eingabe akzeptieren soll. Ich brauche eine Möglichkeit, um sicherzustellen, dass hier nichts anderes eingegeben wird.

Ich habe bereits einen keyListener an dieses Steuerelement angehängt. Nach dem Entfernen des anderen Codes, den dieser Listener verarbeiten soll, habe ich Folgendes:

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

Wie Sie sehen, versuche ich, mit dem KeyCode zu überprüfen, ob die gerade gedrückte Taste in den Bereich von Ganzzahlen fällt. Das scheint zu funktionieren. Was ich aber tun möchte, ist, den Eintrag einfach zu ignorieren, wenn er außerhalb dieses Bereichs liegt. Der Code e.setKeyChar('') sollte damit umgehen, funktioniert aber nicht. Der Code wird kompiliert, hat jedoch keine sichtbaren Auswirkungen.

Kann mir jemand sagen, ob ich auf dem richtigen Weg bin? Womit kann ich e.setKeyChar('') ersetzen, damit dies funktioniert? Oder gehe ich total in die falsche Richtung?

Vielen Dank.

38
Alex

Verwenden Sie hierfür keinen KeyListener, da Sie viel vermissen werden, einschließlich des Einfügens von Text. Auch ein KeyListener ist ein sehr einfaches Konstrukt und sollte daher in Swing-Anwendungen vermieden werden.

Die Lösung wurde in SO bereits mehrfach beschrieben: Verwenden Sie einen DocumentFilter . Es gibt einige Beispiele auf dieser Seite, einige von mir geschrieben.

Zum Beispiel: sing-documentfilter-filterbypass

Schauen Sie sich auch die Hilfe zum Tutorial an: Implementieren eines DocumentFilter .

Bearbeiten

Zum Beispiel:

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
      }

   }
}

Warum ist das wichtig?

  • Was passiert, wenn der Benutzer zum Einfügen von Daten in die Textkomponente Kopieren und Einfügen verwendet? Kann ein KeyListener das verpassen?
  • Sie möchten anscheinend überprüfen, ob die Daten ein int darstellen können. Was ist, wenn sie numerische Daten eingeben, die nicht passen?
  • Was ist, wenn Sie dem Benutzer erlauben möchten, später doppelte Daten einzugeben? In wissenschaftlicher Notation?

Sie können auch JFormattedTextField verwenden, was sehr viel einfacher ist. Beispiel:

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

Ich kann nicht glauben, dass ich diese einfache Lösung noch nirgends auf Stapelüberlauf gefunden habe, sie ist bei weitem die nützlichste. Das Ändern des Dokuments oder des DocumentFilter funktioniert nicht für JFormattedTextField. Peter Tsengs Antwort kommt sehr nahe.

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);
21
Umi

Hier ist ein Ansatz, der einen Keylistener verwendet, aber keyChar (anstelle von keyCode) verwendet:

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

Ein anderer Ansatz (der für mich persönlich fast so kompliziert ist wie das JTree-Modell von Swing) ist die Verwendung formatierter Textfelder:

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

13
paulsm4

Früher habe ich den Key Listener verwendet, aber ich bin mit diesem Ansatz sehr gescheitert. Der empfohlene Ansatz besteht darin, bereits einen DocumentFilter zu verwenden. Im Folgenden finden Sie eine Dienstprogrammmethode, die ich zum Erstellen von Textfeldern mit nur Zahleneingabe erstellt habe. Pass nur auf, dass es auch Single "dauern wird." Zeichen auch, da es für die Dezimaleingabe verwendet werden kann.

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

Wenn Sie nach dem Loslassen der Taste Ganzzahlen in JtextField1 eingeben, wechselt das Programm zu inside try. Bei allen anderen Zeichen wird NumberFormatException ausgelöst. Wenn Sie im catch eine leere Zeichenfolge auf jTextField1 setzen, kann der Benutzer keine anderen Schlüssel als positive Zahlen eingeben, da JTextField1 bei jedem fehlerhaften Versuch gelöscht wird.

 //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("");
    }
}   
4
user3498019