Restringir la entrada de JTextField a enteros [duplicado]

Resuelto AndroidDev asked hace 12 años • 6 respuestas

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.

AndroidDev avatar Jun 19 '12 08:06 AndroidDev
Aceptado

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?
Hovercraft Full Of Eels avatar Jun 19 '2012 01:06 Hovercraft Full Of Eels

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());
}
Peter Tseng avatar Apr 26 '2013 04:04 Peter Tseng