Java - Se bloquea tecla backspace en un JFormatedTextFiel

 
Vista:
Imágen de perfil de Diego
Val: 41
Ha aumentado su posición en 6 puestos en Java (en relación al último mes)
Gráfica de Java

Se bloquea tecla backspace en un JFormatedTextFiel

Publicado por Diego (13 intervenciones) el 05/01/2021 03:09:02
Saludos. Vengo aquí para intentar resolver una acción que aunque no genere un problema grave me gustaría saber si se puede resolver. La cuestión es la siguiente : tengo un JFormattedTextField en el cual solo quiero que permita escribir números del 1 al 20. Eso lo he conseguido usando la subclase NumberFormatter, pero lo que ocurre es que al iniciar el componente y escribir un dígito ya luego no puedo borrarlo solo puedo cambiarlo si hago una selección con el click sostenido del ratón o usando la tecla shift, pero con la tecla backspace no puedo borrarlo. Lo curioso es que el segundo dígito que escriba si permite usar la tecla antes mencionada. ¿Tendré que crear algún método para eso? ¿O la subclase NumberFormatter ya tendrá uno? Adjunto la porción del código del componente. Gracias de antemano
1
2
3
4
5
6
7
8
9
10
11
12
{
    NumberFormatter n = new NumberFormatter();
    n.setAllowsInvalid(false);
    n.setMaximum(20);
    ftxtFuer = new JFormattedTextField(n);
    ftxtFuer.setBorder(BorderFactory.createMatteBorder(1, 5, 3, 2, new Color(205, 149, 12)));
    ftxtFuer.setOpaque(false);
    ftxtFuer.setBounds(75, 135, 30, 30);
    ftxtFuer.setFont(new Font("Indie Flower", Font.BOLD, 15));
    ftxtFuer.setHorizontalAlignment(SwingConstants.CENTER);
    this.add(ftxtFuer);
}
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
Imágen de perfil de Diego
Val: 41
Ha aumentado su posición en 6 puestos en Java (en relación al último mes)
Gráfica de Java

Se bloquea tecla backspace en un JFormatedTextFiel

Publicado por Diego (13 intervenciones) el 06/01/2021 01:29:03
Gracias. Revisaré la información para ver si puedo hacer lo que deseo en el componente.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Kabuto
Val: 3.428
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

Se bloquea tecla backspace en un JFormatedTextFiel

Publicado por Kabuto (981 intervenciones) el 06/01/2021 01:16:18
Puedes enfocarlo de otra manera, usando un KeyListener que compruebe lo que se está escribiendo.
Si no es un valor entero (letras, símbolos..) que directamente lo borre.
Si es un valor entero, que solo lo admita entre 1 y 20.

Prueba este programa a ver si te convence, y lo adaptas al tuyo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public class UnoaVeinte extends JFrame{
 
	private JTextField campo;
 
	public UnoaVeinte() {
 
		campo = new JTextField(4);
		campo.setHorizontalAlignment(SwingUtilities.CENTER);
		campo.addKeyListener(new Solo20());
 
 
		JPanel panel = new JPanel();
		panel.setBorder(BorderFactory.createEmptyBorder(30, 50, 30, 50));
		panel.add(campo);
		add(panel);
 
		setTitle("1 a 20");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setSize(300, 200);
		setLocationRelativeTo(null);
		setVisible(true);
	}
 
	/**
	 * Clase que implementa la interfaz KeyListener.
	 * Al aplicarla a un campo de texto, comprueba lo que se
	 * está escribiendo y solo admite teclear un valor entero
	 * entre 1 y 20.
	 * Si se teclea un valor inferior automáticamente lo cambia por el valor mínimo 1.
	 * Si se teclea un valor superior lo cambia por el valor máximo 20.
	 */
	private class Solo20 implements KeyListener {
 
		@Override
		public void keyTyped(KeyEvent e) {
			//Nada que hacer aquí
		}
 
		@Override
		public void keyPressed(KeyEvent e) {
			//Nada que hacer aquí
		}
 
		@Override
		public void keyReleased(KeyEvent e) {
			try {
				int valor = Integer.parseInt(campo.getText());
				if (valor < 1) {
					campo.setText("1");
					Toolkit.getDefaultToolkit().beep(); //Sistema operativo hace un sonido de advertencia
					campo.selectAll(); //Seleccionamos el texto para que el usuario perciba que ha cambiado.
				}
				else if (valor > 20) {
					campo.setText("20");
					Toolkit.getDefaultToolkit().beep();
					campo.selectAll();
				}
			}
			catch(NumberFormatException ex) {
				//Usuario ha tecleado letras o símbolos
				campo.setText(null);
			}
		}
	}
 
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				new UnoaVeinte();
			}
		});
	}
 
}
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
Imágen de perfil de Diego
Val: 41
Ha aumentado su posición en 6 puestos en Java (en relación al último mes)
Gráfica de Java

Se bloquea tecla backspace en un JFormatedTextFiel

Publicado por Diego (13 intervenciones) el 06/01/2021 01:35:29
Ok, gracias. Tocará implementar un método como el que plantea. ¿Ese método podría aplicarlo a varios campos sin necesidad de crear más métodos cierto? ¿Hasta campos que estén en otras clases verdad?
PD: Soy un aficionado no me dedico a la programación.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Kabuto
Val: 3.428
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

Se bloquea tecla backspace en un JFormatedTextFiel

Publicado por Kabuto (981 intervenciones) el 06/01/2021 14:56:14
Sí.
De hecho, la clase que implementa el KeyListener se puede escribir como una clase separada en su propio archivo Java.

Se puede hacer una clase que herede de JTextField e implemente la interface KeyListener.
En su constructor le podemos incluso indicar cuantas columnas tendrá el campo de texto y cuál es el valor mínimo y máximo que ha de aceptar.
Así no tiene por qué ser siempre de 1 a 20, los valores límite los decidimos al construir el objeto.

EL código que pongo a continuación podría ser dicha clase. Incluyo un pequeño cambio en el KeyListener y es que ahora sí admite el símbolo "negativo" -
... por si queremos que los valores límite admitan números negativos.

El código que puse antes esto no era posible, porque se rechazaba cualquier letra o símbolo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class CampoLimitado extends JTextField implements KeyListener{
 
	private int minimo;
	private int maximo;
 
	public CampoLimitado(int columnas, int valMin, int valMax) {
		super(columnas); //Columnas que tendrá el campo de texto
		minimo = valMin; //Valor mínimo aceptable
		maximo = valMax; //Valor máximo aceptable
		setHorizontalAlignment(SwingUtilities.CENTER); //Texto centrado
		addKeyListener(this); //Aplicamos KeyListener al campo de texto.
	}
 
	@Override
	public void keyTyped(KeyEvent e) {
		//Nada que hacer aquí
	}
 
	@Override
	public void keyPressed(KeyEvent e) {
		//Nada que hacer aquí
	}
 
	@Override
	public void keyReleased(KeyEvent e) {
		try {
			int valor = Integer.parseInt(getText());
			if (valor < minimo) {
				setText(Integer.toString(minimo));
				Toolkit.getDefaultToolkit().beep(); //Sistema operativo hace un sonido de advertencia
				selectAll(); //Seleccionamos el texto para que el usuario perciba que ha cambiado.
			}
			else if (valor > maximo) {
				setText(Integer.toString(maximo));
				Toolkit.getDefaultToolkit().beep();
				selectAll();
			}
		}
		catch(NumberFormatException ex) {
			//Uusario ha tecleado letras o símbolos
			if (!getText().equals("-")) //Solo aceptamos símbolo negativo
				setText(null);
		}
	}
 
}

Teniendo esta clase escrita, la podemos aplicar en cualquier otra clase.
En lugar de agregar objetos de la clase JTextField, agregaremos objetos de la clase CampoLimitado (que en realidad es un JTextField con el KeyListener ya aplicado).

Abajo pongo un ejemplo donde usando esta misma clase, podemos crear tres campos de texto cada uno con sus propios valores mínimos y máximos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class TestCampos extends JFrame{
 
	private CampoLimitado campo1a20;
	private CampoLimitado campo50a99;
	private CampoLimitado campoMenos100a100;
 
	public TestCampos() {
 
		campo1a20 = new CampoLimitado(4,1,20); //En constructor indicamos columnas, mínimo y máximo
		campo50a99 = new CampoLimitado(4,50,99);
		campoMenos100a100 = new CampoLimitado(4,-100,100);
 
		JPanel panel1 = new JPanel();
		panel1.add(new JLabel("Solo de 1 a 20: "));
		panel1.add(campo1a20);
 
		JPanel panel2 = new JPanel();
		panel2.add(new JLabel("Solo de 50 a 99: "));
		panel2.add(campo50a99);
 
		JPanel panel3 = new JPanel();
		panel3.add(new JLabel("Solo de -100 a 100: "));
		panel3.add(campoMenos100a100);
 
		JPanel principal = new JPanel();
		principal.setLayout(new BoxLayout(principal, BoxLayout.Y_AXIS));
		principal.add(panel1);
		principal.add(panel2);
		principal.add(panel3);
		principal.setBorder(BorderFactory.createEmptyBorder(50, 50, 50, 50));
 
		add(principal);
 
		setTitle("Test Campos Limitados");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		pack();
		setLocationRelativeTo(null);
		setVisible(true);
	}

Sin embargo, si lo pruebas surge un pequeño problemita y se percibe sobre todo en el segundo campo, el que admite valores entre 50 y 99.

Si quieres poner por ejemplo 65, que es un valor admitido, al pulsar primero el 6, como es menor que 50, el KeyListener te lo fulmina.
Hay que teclear el 6 y el 5 muy rápido para que te deje completar la cifra.
Esto, en un escenario real, podría ser muy incómodo para los usuarios. No es lógico que el programa les obligue a teclear a la velocidad de la luz je je...

Habría que buscar una solución a esto.... y me temo que la mejor solución sería cambiar de Listener..

Con KeyListener ha quedado guay, porque te corrige en "tiempo real" mientras tecleas... pero ya hemos visto que en determinados casos te corrige tan rápido que no te da tiempo a completar una cifra que sí es aceptable.

Podemos probar con FocusListener.
Este Listener comprueba cuándo un objeto Swing recibe el "foco" y cuándo lo pierde.

Un JTextField recibe el foco cuando nos posicionamos en él para escribir. Mientra tenga el foco, no es necesario que hagamos nada.

Pero cuando lo pierda, porque nos hemos movido a otro campo, o hemos pulsado en otro sitio del formulario, o lo que sea... en ese momento es cuando podemos comprobar que es lo que ha tecleado y ver si está dentro de los valores mínimos y máximo.

Con este Listener, no nos corrige en tiempo real, podremos escribir cualquier cosa en él. Nos corregirá después, y esto tiene la ventaja de que ahora no hay que teclear a la velocidad de la luz números que tengan más de una cifra xD

Así que la clase CampoLimitado, la podemos reescribir con estos cambios. Los marco en negrita.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class CampoLimitado extends JTextField implements FocusListener{
 
	private int minimo;
	private int maximo;
 
	public CampoLimitado(int columnas, int valMin, int valMax) {
		super(columnas); //Columnas que tendrá el campo de texto
		minimo = valMin; //Valor mínimo aceptable
		maximo = valMax; //Valor máximo aceptable
		setHorizontalAlignment(SwingUtilities.CENTER); //Texto centrado
		addFocusListener(this); //Aplicamos FocusListener
	}
 
	@Override
	public void focusGained(FocusEvent e) {
		//Nada que hacer aquí
	}
 
	@Override
	public void focusLost(FocusEvent e) {
		try {
			int valor = Integer.parseInt(getText());
			if (valor < minimo) {
				setText(Integer.toString(minimo));
				Toolkit.getDefaultToolkit().beep(); //Sistema operativo hace un sonido de advertencia
				selectAll(); //Seleccionamos el texto para que el usuario perciba que ha cambiado.
			}
			else if (valor > maximo) {
				setText(Integer.toString(maximo));
				Toolkit.getDefaultToolkit().beep();
				selectAll();
			}
		}
		catch(NumberFormatException ex) {
			//Usuario no ha indicado ningún valor que pueda convertirse a número
			setText(null);
		}
 
	}
 
}

Como puedes ver el código es prácticamente el mismo.
Solo cambia que ahora la comprobación del texto introducido se hace cuando el usuario abandona el campo de texto.
Y ya no ocurre el problema de tener que teclear tan rápido.


Todo esto ha sido interesante, porque hemos podido probar como responden estos dos Listener y que diferencias tienen uno con otro.

Si tienes alguna duda sobre todo esto, pregunta lo que sea.

Un saludo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
Imágen de perfil de Diego
Val: 41
Ha aumentado su posición en 6 puestos en Java (en relación al último mes)
Gráfica de Java

Se bloquea tecla backspace en un JFormatedTextFiel

Publicado por Diego (13 intervenciones) el 07/01/2021 02:01:21
¡Maravillo! Es usted muy amable, gracias por compartir su conocimiento. Guardaré los códigos he iré "cacharreando" a ver que descubro. Muy agradecido.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar