Restricción de entrada de JTextField a enteros

Sé que esta pregunta debe haber sido hecha y respondida un millón de veces, pero simplemente no puedo encontrar una solución fácil. Tengo un JTextField que solo debe aceptar enteros positivos como entrada. Necesito una forma de asegurarme de que nada más ingrese aquí.

Ya tengo un KeyListener conectado a este control. Al eliminar el otro código que este oyente está ahí para manejar, tengo esto:

txtAnswer.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); /* Restrict input to only integers */ if (key  105) e.setKeyChar(''); }; }); 

Como puede ver, estoy tratando de usar el KeyCode para verificar si la tecla que acaba de presionar está dentro del rango de los números enteros. Esto parece funcionar Pero lo que quiero hacer es simplemente ignorar la entrada si cae fuera de este rango. El código e.setKeyChar('') estaba destinado a manejar esto, pero no funciona. El código se comstackrá, pero no tiene ningún efecto visible.

¿Alguien puede decirme si estoy en el camino correcto? ¿Con qué puedo reemplazar e.setKeyChar('') para que funcione? ¿O estoy yendo totalmente en la dirección incorrecta?

Gracias.

No use KeyListener para esto ya que extrañará mucho, incluida la pegada de texto. Además, KeyListener es una construcción de muy bajo nivel y, como tal, debe evitarse en las aplicaciones Swing.

La solución ha sido descrita muchas veces en SO: Use un DocumentFilter . Hay varios ejemplos de esto en este sitio, algunos escritos por mí.

Por ejemplo: using-documentfilter-filterbypass

También para obtener ayuda con el 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é sucede si el usuario usa copiar y pegar para insertar datos en el componente de texto? Un KeyListener puede perder esto?
  • Parece que desea comprobar que los datos pueden representar un int. ¿Qué pasa si ingresan datos numéricos que no encajan?
  • ¿Qué sucede si desea permitir que el usuario ingrese datos dobles más adelante? En notación científica?

También puede usar JFormattedTextField , que es mucho más fácil 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()); } 

No puedo creer que aún no haya encontrado esta solución simple en el desbordamiento de la stack, es de lejos la más útil. Cambiar el documento o DocumentFilter no funciona para JFormattedTextField. La respuesta de Peter Tseng es muy cercana.

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

Aquí hay un enfoque que usa un keylistener, pero usa el keyChar (en lugar del código clave):

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

Otro enfoque (que personalmente encuentro casi tan complicado como el modelo JTree de Swing) es usar campos de texto formateados:

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

Solía ​​usar Key Listener para esto, pero fallé mucho con ese enfoque. El mejor enfoque ya recomendado es usar un DocumentFilter. A continuación se muestra un método de utilidad que creé para construir campos de texto con solo entrada numérica. Solo ten en cuenta que también se llevará solo ‘.’ personaje también, ya que es utilizable para la entrada decimal.

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

Cuando escriba números enteros en JtextField1 después de la liberación de la tecla, irá a try interno, para cualquier otro carácter arrojará NumberFormatException. Si configura una cadena vacía para jTextField1 dentro de la captura, el usuario no podrá escribir ninguna otra clave, excepto los números positivos porque JTextField1 se borrará por cada bash fallido.

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