Java - ¿Como capturo toda la cadena de un JtextField sin que el keyRelease escuche caracter por caracter?

 
Vista:

¿Como capturo toda la cadena de un JtextField sin que el keyRelease escuche caracter por caracter?

Publicado por julian garcia (1 intervención) el 27/05/2020 20:07:06
Estoy tratando de realizar un cálculo a medida que voy escribiendo un número en un JTextField.
Si el numero es de un dígito... todo correcto, hace las operaciones adecuadamente.
En caso de que el número tenga más de un dígito entonces ahí entra en conflicto, ejemplo:

- Si el número es 1 ... ok

- Si el número es 12 ... primero hace calculos con el 1 y entrega resultados pero vuelve y realiza calculos en la segunda iteración con el número 12.

-Si el número es 123 ... los primeros calculos lo hace con el 1, luego con el 12 y luego con el 123

Quisiera saber si hay una manera para que el evento KEYRELEASE me permita escribir y despues de unos cuantos milisegundos escuche lo que escribí y ahora si haga calculos
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 Kabuto
Val: 3.428
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

¿Como capturo toda la cadena de un JtextField sin que el keyRelease escuche caracter por caracter?

Publicado por Kabuto (1381 intervenciones) el 28/05/2020 20:07:38
KeyRelease, como su nombre indica, se activa cada vez que se suelta una tecla, así que no puedes evitar que con cada pulsación/liberación de tecla se active el Listener.

La solución sencilla sería no usar KeyListener, si no poner un botón y que el usuario decida cuando se puede computar el campo de texto pulsando el botón.

Pero, pensando en una alternativa, se me ha ocurrido una solución "compleja".
Bueno, no es tan difícil, lo que no se si es práctica.

Mira, esto es un programa escrito rápido con un campo y una etiqueta.
Si se ejecuta, se aprecia el "problema" que tu tienes, cada vez que se suelta la tecla, se hace una operación (multiplico por 10) con el valor actual del campo de texto.
La operación es inmediata, no "espera" a que termines de teclear todo el valor que se quiere introducir.

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
public class DelayKeyRelease extends JFrame{
 
	private JTextField campo;
	private JLabel etiqueta;
 
	public DelayKeyRelease() {
 
		campo = new JTextField(10);
		campo.addKeyListener(new LeerTecla());
		etiqueta = new JLabel("0");
 
		JPanel pnCampo = new JPanel();
		pnCampo.setBorder(BorderFactory.createEmptyBorder(75, 75, 50, 75));
		pnCampo.add(campo);
 
		JPanel pnEtiq = new JPanel();
		pnEtiq.setBorder(BorderFactory.createEmptyBorder(50, 75, 75, 75));
		pnEtiq.add(etiqueta);
 
		setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
		add(pnCampo);
		add(pnEtiq);
 
		setTitle("KeyRelease");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		pack();
		setLocationRelativeTo(null);
		setVisible(true);
	}
 
	private class LeerTecla implements KeyListener {
 
		@Override
		public void keyTyped(KeyEvent e) { }
 
		@Override
		public void keyPressed(KeyEvent e) { }
 
		@Override
		public void keyReleased(KeyEvent e) {
			try {
				int valor = Integer.parseInt(campo.getText());
				etiqueta.setText(Integer.toString(valor * 10));
			}catch(Exception ex) {
				etiqueta.setText("0");
			}
		}
 
	}
 
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				new DelayKeyRelease();
			}
		});
	}
 
}


Bien, ¿como hacer que tras la primera pulsación de tecla el programa nos de unos segundos para que terminemos de teclear antes de hacer ningún computo?

Se me ha ocurrido añadirle un objeto de la clase Thread, es decir, un hilo de ejecución paralelo al programa principal que nos va a dar tres segundos antes de hacer ningún computo.
Quizás tres segundos son demasiados, pero los he puesto así para exagerar un poco y que se aprecie claramente que hay un delay entre la primera pulsación hasta que se realizan los computos.

Lo agrego como un objeto más de la clase principal y lo inicializo en el constructor:

1
2
3
4
5
6
7
8
9
10
11
12
public class DelayKeyRelease extends JFrame{
 
	private JTextField campo;
	private JLabel etiqueta;
	private Computar computar;
 
	public DelayKeyRelease() {
 
		computar = new Computar();
		campo = new JTextField(10);
		campo.addKeyListener(new LeerTecla());
		etiqueta = new JLabel("0");

Entonces, el KeyReleased lo que hará será comprobar si este Thread llamado computar, esta activo o no.
Si no está activo, lo pondrá en marcha y comenzará el delay de tres segundos.
Si ya está activo, es porque los tres segundos están contando, entonces no hará nada y este evento KeyListener será "consumido" (ignorado)

1
2
3
4
5
6
7
8
9
10
public void keyReleased(KeyEvent e) {
			//Comprobamos si el temporizador esta activo
			if (computar.isAlive()) {//Temporizadorr SÍ está activo
				e.consume(); //Ignoramos este evento
			}
			else {
				computar = new Computar();
				computar.start(); //No lo está, lo activamos
			}
		}

Cuando el Thread se activa, lo primero que hace es.. "echarse a dormir" durante 3 segundos.
Cuando se despierta, entonces es quien se encarga de recoger el valor del campo de texto y computarlo.
Se puede elegir los segundos modificando el valor de la constante DELAY
Tan sencillo como esto:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Computar extends Thread {
 
		private final int DELAY = 3; //Aqui decidimos cuantos segundos esperar
 
		@Override
		public void run() {
			try {
				sleep(DELAY*1000L);
				int valor = Integer.parseInt(campo.getText());
				etiqueta.setText(Integer.toString(valor * 10));
			}catch(Exception ex) {
				etiqueta.setText("0");
			}
		}
	}

Y listo. Pego ahora el código completo, si lo pruebas, verás que tras la primera pulsación, tenemos tres segundos para seguir tecleando hasta que se haga el computo.
Una vez hecho el computo, la siguiente pulsación volverá a iniciar otro periodo de tres segundos hasta el siguiente computo.

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
76
77
78
79
80
public class DelayKeyRelease extends JFrame{
 
	private JTextField campo;
	private JLabel etiqueta;
	private Computar computar;
 
	public DelayKeyRelease() {
 
		computar = new Computar();
		campo = new JTextField(10);
		campo.addKeyListener(new LeerTecla());
		etiqueta = new JLabel("0");
 
		JPanel pnCampo = new JPanel();
		pnCampo.setBorder(BorderFactory.createEmptyBorder(75, 75, 50, 75));
		pnCampo.add(campo);
 
		JPanel pnEtiq = new JPanel();
		pnEtiq.setBorder(BorderFactory.createEmptyBorder(50, 75, 75, 75));
		pnEtiq.add(etiqueta);
 
		setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
		add(pnCampo);
		add(pnEtiq);
 
		setTitle("KeyRelease");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		pack();
		setLocationRelativeTo(null);
		setVisible(true);
	}
 
	private class LeerTecla implements KeyListener {
 
		@Override
		public void keyTyped(KeyEvent e) { }
 
		@Override
		public void keyPressed(KeyEvent e) { }
 
		@Override
		public void keyReleased(KeyEvent e) {
			//Comprobamos si el temporizador esta activo
			if (computar.isAlive()) {//Temporizado SÍ está activo
				e.consume(); //Ignoramos este evento
			}
			else {
				computar = new Computar();
				computar.start(); //No lo esta, lo activamos
			}
		}
 
	}
 
	class Computar extends Thread {
 
		private final int DELAY = 3; //Aqui decidimos cuantos segundos esperar
 
		@Override
		public void run() {
			try {
				sleep(DELAY*1000L);
				int valor = Integer.parseInt(campo.getText());
				etiqueta.setText(Integer.toString(valor * 10));
			}catch(Exception ex) {
				etiqueta.setText("0");
			}
		}
	}
 
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				new DelayKeyRelease();
			}
		});
	}
 
}
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

¿Como capturo toda la cadena de un JtextField sin que el keyRelease escuche caracter por caracter?

Publicado por Tom (1831 intervenciones) el 28/05/2020 20:23:09
Es bastante instructivo y seguramente funcione bien.
Lo malo es que tarde o temprano puede fallar, ya que las modificaciones a los objetos gráficos solamente deben hacerse desde el propio thread de swing.

Quizás podrías hacer lo mismo (o parecido) usando https://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html.
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

¿Como capturo toda la cadena de un JtextField sin que el keyRelease escuche caracter por caracter?

Publicado por Tom (1831 intervenciones) el 28/05/2020 20:50:40
Algo parecido a:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Computar extends SwingWorker<Void, Integer> {
		private final int DELAY = 3; //Aqui decidimos cuantos segundos esperar
 
		@Override
		protected Void doInBackground() throws Exception {
			try {
				Thread.sleep(DELAY * 1000L);
				int valor = Integer.parseInt(campo.getText());
				publish(valor * 10);
			} catch(Exception ex) {
				etiqueta.setText("0");
			}
			return null;
		}
		@Override
		protected void process(List<Integer> datas) {
			for(Integer i : datas) {
				etiqueta.setText(i.toString());
			}
		}
	}
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 Kabuto
Val: 3.428
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

¿Como capturo toda la cadena de un JtextField sin que el keyRelease escuche caracter por caracter?

Publicado por Kabuto (1381 intervenciones) el 28/05/2020 22:52:50
¡¡Gracias por el ejemplo!!
SwingWorker es una de las cosillas que tengo pendientes de empaparme bien como utilizar.

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
0
Comentar
Imágen de perfil de Franklin
Val: 456
Bronce
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

¿Como capturo toda la cadena de un JtextField sin que el keyRelease escuche caracter por caracter?

Publicado por Franklin (179 intervenciones) el 28/05/2020 23:02:39
Una consulta, funcionaría para este problema usar un DocumentListener con sus metodos Update/Insert/remove?
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

¿Como capturo toda la cadena de un JtextField sin que el keyRelease escuche caracter por caracter?

Publicado por Tom (1831 intervenciones) el 29/05/2020 12:05:58
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
public class DelayKeyRelease extends JFrame {
	private JTextField campo;
	private JLabel etiqueta;
	private Computar computar;
 
	public DelayKeyRelease() {
		campo = new JTextField(10);
		etiqueta = new JLabel("0");
		JPanel pnCampo = new JPanel();
		pnCampo.setBorder(BorderFactory.createEmptyBorder(75, 75, 50, 75));
		pnCampo.add(campo);
		JPanel pnEtiq = new JPanel();
		pnEtiq.setBorder(BorderFactory.createEmptyBorder(50, 75, 75, 75));
		pnEtiq.add(etiqueta);
		setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
		add(pnCampo);
		add(pnEtiq);
		setTitle("KeyRelease");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		pack();
		setLocationRelativeTo(null);
		campo.getDocument().addDocumentListener(new LeerTecla());
	}
 
	private class LeerTecla implements DocumentListener {
		@Override
		public void insertUpdate(DocumentEvent e) {
			testWorker();
		}
		@Override
		public void removeUpdate(DocumentEvent e) {
			testWorker();
		}
		@Override
		public void changedUpdate(DocumentEvent e) {
			testWorker();
		}
		/* */
		private void testWorker() {
			if(computar == null) {
				computar = new Computar();
				computar.execute();
			}
		}
	}
	class Computar extends SwingWorker<Void, Integer> {
		private final int DELAY = 3; //Aqui decidimos cuantos segundos esperar
 
		@Override
		protected Void doInBackground() throws Exception {
			try {
				while(!isCancelled()) {
					Thread.sleep(DELAY * 1000L);
					int valor = Integer.parseInt(campo.getText());
					publish(valor * 10);
				}
			} catch(Exception ex) {
				etiqueta.setText("Error");
			}
			return null;
		}
		@Override
		protected void process(List<Integer> datas) {
			for(Integer i : datas) {
				etiqueta.setText(i.toString());
			}
		}
	}
	/* */
	public static void main(String[] args) {
		new DelayKeyRelease().setVisible(true);
	}
}
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