Restringir la entrada de JTextField a enteros [duplicado]
Sé que esta pregunta debe haber sido formulada y respondida un millón de veces, pero no puedo encontrar una solución fácil. Tengo un JTextField que está destinado a aceptar sólo números enteros positivos como entrada. Necesito una manera de asegurarme de que no se ingrese nada más aquí.
Ya tengo un keyListener adjunto a este control. Al eliminar el otro código que este oyente debe manejar, tengo esto:
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('');
};
});
Como puede ver, estoy intentando usar KeyCode para verificar si la tecla que acabo de presionar está dentro del rango de números enteros. Esto parece funcionar. Pero lo que quiero hacer es simplemente ignorar la entrada si queda fuera de este rango. El códigoe.setKeyChar('')
estaba destinado a manejar esto, pero no funciona. El código se compilará, pero no tiene ningún efecto visible.
¿Alguien puede decirme si estoy en el camino correcto? ¿Qué puedo reemplazar?e.setKeyChar('')
para que esto funcione? ¿O estoy yendo totalmente en la dirección equivocada?
Gracias.
No utilice un KeyListener para esto, ya que se perderá muchas cosas, incluido el pegado de texto. Además, KeyListener es una construcción de muy bajo nivel y, como tal, debe evitarse en aplicaciones Swing.
La solución se ha descrito muchas veces en SO: Utilice un DocumentFilter . Hay varios ejemplos de esto en este sitio, algunos escritos por mí.
Por ejemplo: usando-documentfilter-filterbypass
También para obtener ayuda tutorial, consulte: Implementación de un DocumentFilter .
Editar
Por ejemplo:
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
}
}
}
¿Porque es esto importante?
- ¿Qué pasa si el usuario usa copiar y pegar para insertar datos en el componente de texto? ¿Un KeyListener puede perderse esto?
- Parece que desea comprobar que los datos pueden representar un int. ¿Qué pasa si ingresan datos numéricos que no encajan?
- ¿Qué pasa si desea permitir que el usuario luego ingrese datos dobles? ¿En notación científica?
También puedes usar JFormattedTextField
, que es mucho más sencillo de usar. Ejemplo:
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());
}