Swing - Thread.sleep () stops JTextField.setText ()

Possible duplicate:
using sleep () for a single thread

I am having problems with JTextField.setText () when using Thread.sleep (). This is for the basic calculator that I am doing. When the input in the input field does not match the correct format, I want "INPUT ERROR" to appear in the output field for 5 seconds, and then to clear it. The setText () method worked when I just set the text once to "INPUT ERROR" and, after printing the text between them, I found that it works with both this and setText ("") one after the other. The problem occurs when I put Thread.sleep () between them. Here is the version of the SSCCE code:

import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.regex.Pattern; import javax.swing.*; public class Calc { static Calc calc = new Calc(); public static void main(String args[]) { GUI gui = calc.new GUI(); } public class GUI implements ActionListener { private JButton equals; private JTextField inputField, outputField; public GUI() { createFrame(); } public void createFrame() { JFrame baseFrame = new JFrame("Calculator"); baseFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel contentPane = new JPanel(); BoxLayout layout = new BoxLayout(contentPane, BoxLayout.Y_AXIS); contentPane.setLayout(layout); baseFrame.setContentPane(contentPane); baseFrame.setSize(320, 100); equals = new JButton("="); equals.addActionListener(this); inputField = new JTextField(16); inputField.setHorizontalAlignment(JTextField.TRAILING); outputField = new JTextField(16); outputField.setHorizontalAlignment(JTextField.TRAILING); outputField.setEditable(false); contentPane.add(inputField); contentPane.add(outputField); contentPane.add(equals); contentPane.getRootPane().setDefaultButton(equals); baseFrame.setResizable(false); baseFrame.setLocation(100, 100); baseFrame.setVisible(true); } /** * When an action event takes place, the source is identified and the * appropriate action is taken. */ @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == equals) { inputField.setText(inputField.getText().replaceAll("\\s", "")); String text = inputField.getText(); System.out.println(text); Pattern equationPattern = Pattern.compile("[\\d(][\\d-+*/()]+[)\\d]"); boolean match = equationPattern.matcher(text).matches(); System.out.println(match); if (match) { // Another class calculates } else { try { outputField.setText("INPUT ERROR"); // This doesn't appear Thread.sleep(5000); outputField.setText(""); } catch (InterruptedException e1) { } } } } } } 

I don't actually use a nested class, but I wanted it to be contained in the same class for you. Sorry what the GUI looks like, but again it was for shortening the code. The important section ( if (e.getSource() == equals) ) remains unchanged from my code. The easiest way to give incorrect input is to use letters.

+4
source share
3 answers

When you use Thread.sleep() , you do this in the main thread. This freezes gui for five seconds, then updates the outputField . When this happens, it uses the last empty text that is empty.

It is much better to use Swing Timers and here is an example that does what you are trying to accomplish:

 if (match) { // Another class calculates } else { outputField.setText("INPUT ERROR"); ActionListener listener = new ActionListener(){ public void actionPerformed(ActionEvent event){ outputField.setText(""); } }; Timer timer = new Timer(5000, listener); timer.setRepeats(false); timer.start(); } 
+11
source

As Philippe Whitehouse states in his answer, you are blocking the Swing Event Dispatch Thread event flow with a call to Thread.sleep(...) .

Given that you already took the time to create an ActionListener , it would be easiest to use javax.swing.Timer to control text clearing. To do this, you can add a field to your GUI class:

  private Timer clearTimer = new Timer(5000, this); 

In the constructor for the GUI disable the snooze function, since you really only need one shot:

  public GUI() { clearTimer.setRepeats(false); createFrame(); } 

Then actionPerformed can be changed to use this to start the timer / clear the field:

  public void actionPerformed(ActionEvent e) { if (e.getSource() == equals) { inputField.setText(inputField.getText().replaceAll("\\s", "")); String text = inputField.getText(); System.out.println(text); Pattern equationPattern = Pattern.compile("[\\d(][\\d-+*/()]+[)\\d]"); boolean match = equationPattern.matcher(text).matches(); System.out.println(match); if (match) { // Another class calculates } else { clearTimer.restart(); outputField.setText("INPUT ERROR"); // This doesn't appear } } else if (e.getSource() == clearTimer) { outputField.setText(""); } } 
+9
source

You do Thread.sleep() in the main Swing thread. This is NOT a good practice. You should use a SwingWorker stream at best.

What happens when it launches the first line by clicking Thread.sleep() .

This prevents the execution of the (main) EDT stream from any of the reviews (as well as preventing the execution of the next line).

You should use javax.swing.Timer to set up a delayed response and not send sleep() calls to the main thread.

+8
source

All Articles