Swing - Thread.Sleep() Stop Jtextfield.Settext() Working

Swing - Thread.sleep() stop JTextField.setText() working

When you use Thread.sleep() you're doing it on the main thread. This freezes the gui for five seconds then it updates the outputField. When that happens, it uses the last set text which is blank.

It's much better to use Swing Timers and here's an example that does what you're 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();
}

DocumentListener with Thread.sleep

Again, use a Swing Timer to do the dirty work. What you do is whenever you edit or delete, call re-start on the Timer to re-set the timer and start it. The restart() method will stop the Timer if it is running.

     public void insertUpdate(DocumentEvent e) {
label.setText(EDITING);
writeDeleteTimer.restart();
}

For example:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

@SuppressWarnings("serial")
public class TextChangedFrame extends JPanel {

public static final String STOPPED_EDITING = "No Longer Editing or Deleting";
private static final String EDITING = "Editing";
private static final String DELETING = "Deleting";
private static final int TIMER_DELAY = 500;
private static final int PREF_W = 400;
private static final int PREF_H = 100;
private JTextField textField = new JTextField("Put your text here");
private JLabel label = new JLabel("You have written: ");
private ActionListener timerListener = new TimerListener();
private Timer writeDeleteTimer = new Timer(TIMER_DELAY, timerListener);

public TextChangedFrame() {
setLayout(new BorderLayout());
add(textField, BorderLayout.CENTER);
add(label, BorderLayout.SOUTH);
textField.getDocument().addDocumentListener(new DocumentListener() {

public void insertUpdate(DocumentEvent e) {
label.setText(EDITING);
writeDeleteTimer.restart();
}

public void removeUpdate(DocumentEvent e) {
label.setText(DELETING);
writeDeleteTimer.restart();
}

public void changedUpdate(DocumentEvent e) {
}
});
}

@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}

private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent evt) {
label.setText(STOPPED_EDITING);
Timer timer = (Timer) evt.getSource();
timer.stop();
}
}

private static void createAndShowGui() {
TextChangedFrame mainPanel = new TextChangedFrame();

JFrame frame = new JFrame("TextChangedFrame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Answer edited: no need to recreate the Timer object. Simply call restart() on it as it will stop the current Timer if it's running.

JFrame is inactive during Thread.sleep(int)

What @sorifiend means is, calling sleep() from an event handler will "lock up" your application's event dispatch thread. The application will not respond to any other user input until the event handler function returns.

If you want the application to be responsive while the calculator is "working", then what you need to do is:

  • Record that the state of the calculator is "working"
  • Disable whatever buttons you don't want the user to press while the calculator is "working", --OR-- change the handlers for those buttons to do something different (simulate jamming the machine?) if they are pressed while in the "working" state.
  • Submit a timer event for some time in the near future (however long the calculation is supposed to take.)
  • In the handler for the timer event, display the result of the calculation, re-enable the disabled buttons, and change the state from "working" back to "idle" (or whatever).

Thread sleep in GUI Action Listener JAVA

Part of the issue is that you're calling Thread.sleep()

That is putting the Main thread to sleep so you're entire application stops executing.

 for(int i=600; i>0;
try{
Thread.sleep(1000);
String cc = ""+i;
lab1.setText(cc);
}

For your application sounds like you need to make a separate thread to run that will then wake up and actually run the alarm.

Maybe try something like this:

Thread t = new Thread(() -> {
for(int i=600; i>0;i-- ){
try{
Thread.sleep(1000);
String cc = ""+i;
lab1.setText(cc);
}
catch(InterruptedException e){
System.out.println("Chyba!");
}
}
});
t.start();

The call to Thread.sleep() should put the sub thread to sleep and not effect the rest of your application.

Please note I'm using arrow notation (->) for the thread. You don't have to. Instead you can simply create a runnable:

Runnable alarmRunnable = new Runnable() {
@Override
public void run() {
for(int i=600; i>0;i-- ){
try{
Thread.sleep(1000);
String cc = ""+i;
lab1.setText(cc);
}
catch(InterruptedException e){
System.out.println("Chyba!");
}
}
}
};

Thread t = new Thread(alarmRunnable);
t.start();

The arrow notation (otherwise known as lambda) I think is cleaner though.

Frequent calls to setText() in multithreaded Swing program

The setText() "method is thread safe, although most Swing methods are not. Please see How to Use Threads for more information."

Addendum: For reference, here's some other approaches to updating on the EDT. Another thing to note is that the action event handler for javax.swing.Timer executes on the EDT. Here's my variation:

import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import javax.swing.text.DefaultCaret;

public class TextTest extends JFrame {

private JTextArea out = new JTextArea();
private PipedInputStream pIn = new PipedInputStream();
private PrintWriter pOut;

public TextTest() {
try {
pOut = new PrintWriter(new PipedOutputStream(pIn));
} catch (IOException e) {
System.err.println("can't init stream");
}

DefaultCaret caret = (DefaultCaret) out.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);

add(new JScrollPane(out));
setSize(300, 500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);

// Start a loop to print to the stream continuously
new Thread() {

public void run() {
for (int i = 0; true; i++) {
pOut.println(i);
}
}
}.start();

// Start a timer to display the text in the stream every 10 ms
new Timer(10, new ActionListener() {

public void actionPerformed(ActionEvent evt) {
try {
out.append(String.valueOf((char) pIn.read()));
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}

public static void main(String[] args) {
new TextTest();
}
}


Related Topics



Leave a reply



Submit