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