JTextField que solo admite digitos

De ChuWiki

Para conseguir que un JTextField sólo admita números (o en general controlar su entrada para que cumpla ciertas características), tenemos muchas opciones disponibles.

Podemos hacer dos grandes grupos de soluciones. El primero son las soluciones que permiten escribir cualquier cosa, pero luego protestan al intentar coger el número. El segundo son las que directamente NO dejan escribir algo no válido.


Admiten cualquier cosa y protestan luego[editar]

JFormattedTextField[editar]

Una opción es usar un JFormattedTextField en vez de un JTextField. Con esto, el código es tan tonto como esto

JFormattedTextField textField1 = new JFormattedTextField (new Integer(3));

o bien

JFormattedTextField textField2 = new JFormattedTextField ();
textField2.setValue(new Integer(3));

y cuando queramos leer, sólo tenemos que hacer

Integer valor = textField1.getValue();

Si el usuario escribe letras, entonces el método getValue() nos devolverá el último valor bueno conocido y el JFormattedTextField modificará su contenido para mostrar ese último valor.

Añadir un FocusLost[editar]

Añadiendo un FocusListener al JTextField, nos enteraremos de cuando se pierde el foco. Podemos entonces verificar si la entrada nos gusta o no.

textField.addFocusListener (new FocusListener()
{
   public void focusLost (FocusEvent e)
   {
      String cadena = textField.getText();
      // Aquí verificamos si la cadena es correcta.
   }
   ...
});


Añadir un InputVerifier[editar]

El InputVerifier es una característica un poco olvidada de Java. Todos los componentes de Swing colaboran entre ellos a la hora de pasarse el foco de unos a otros. Si un componente gana el foco, primero le pregunta al componente que lo pierde (y en concreto a su InputVerifier) si se puede hacer la trasnmisión del foco.

De esta forma, por ejemplo, si escribimos algo en el JTextField y vamos a pulsar un JButton, el JButton antes de ganar el foco preguntará el InputVerifier del JTextField si se puede cambiar el foco del JTextField al JButton. Este es el momento que tiene el JTextField para verificar si su entrada es o no correcta y negarse a perder el foco hasta que lo sea. El resultado es que podemos escribir cosas incorrectas, pero no podremos salir del JTextField hasta que la entrada sea correcta.

El código puede ser como este

textField.setInputVerifier(new InputVerifier()
{
   public boolean verify(JComponent input) {
      JTextField tf = (JTextField) input;
      String cadena = tf.getText();
      // Aqui verificamos si cadena es correcta y devolvemos
      if (cadenaEsCorrecta) return true;
      else return false;
});


No admiten cualquier cosa[editar]

Si queremos ser más restrictivos y no queremos dejar al usuario escribir cualquier cosa, tenemos varios métodos disponibles


Usar una máscara con el JFormattedTextField[editar]

Si usamos un JFormattedTextField con máscara, entonces no podremos escribir nada fuera de esa máscara. Este JFormattedTextField se crea así

try
{
   MaskFormatter mascara = new MaskFormatter("##.##");
   JFormattedTextField textField = new JFormattedTextField(mascara);
   textField.setValue(new Float("12.34"));
}
catch (Exception e)
{
   ...
}

El manejo ahora es igual que en el caso anterior, usando

Double valor =  textField.getValue();

Capturar el teclado[editar]

Otra opción es capturar el teclado y verificar cada pulsación de tecla si es o no correcta

JTextField textField = new JTextField(10);
textField.addKeyListener(new KeyAdapter()
{
   public void keyTyped(KeyEvent e)
   {
      char caracter = e.getKeyChar();

      // Verificar si la tecla pulsada no es un digito
      if(((caracter < '0') ||
         (caracter > '9')) &&
         (caracter != '\b' /*corresponde a BACK_SPACE*/))
      {
         e.consume();  // ignorar el evento de teclado
      }
   }
});

Esta opción está bastante extendida, sin embargo es costosa de hacer bien. Entre las teclas admitidas hemos puesto '\b', que corresponde a BACK_SPACE introducida como char, puesto que si no esa tecla también se ignora y no se puede borrar. Igualmente habría que poner todas las teclas que queremos que funcionen, como Ctrl-C y Ctrl-V para permitir copy-paste, quizás el <enter> para que se dispare el ActionEvent, flechas a la izquierda y derecha, etc, etc.

Si no somos cuidadosos, tendremos un JTextField que no admite otra cosa que no sea números, pero tampoco muchas de las funcionalidades estandard de una caja de texto.

Modificar el Document[editar]

Finalmente, otra opción es crearnos un Document y añadirlo. En el Document tenemos que hacer algo parecido al KeyListener, pero a un nivel más alto. No debemos preocuparnos de las teclas una a una, sino sólo del cacho de texto completo que se quiere añadir, borrar, etc.

La forma más fácil de contruir el Document es heredando de PlainDocument y sobreescribiendo el método que nos interesa.

class LimitadorCaracteres extends PlainDocument
{
   /**
    * Método al que llama el editor cada vez que se intenta insertar caracteres.
    * Sólo debemos verificar arg1, que es la cadena que se quiere insertar en el JTextField
    */
   public void insertString(int arg0, String arg1, AttributeSet arg2) throws BadLocationException
   {
       for (int i=0;i<arg1.length();i++)
          // si no es digit, volvemos
          if (!Character.isDigit(arg1.charAt(i)))
             return;

       // Si todos son digit, insertamos el texto en el JTextField
       super.insertString(arg0, arg1, arg2);
   }
} 

y luego, hay poner este Document en el JTextField

textField.setDocument (new LimitadorCaracteres());


Enlaces[editar]