I'm fairly new to threads and haven't written Java in a long time so bear with me here. I have a very simple GUI. It has a counter, a status label, and two buttons, start and stop respectively.
What I wanted it to do was update my status label using a counter
thread. When I hit start it supposedly starts the counter at 0 and increments it every second
, and when I choose to hit stop
it should suspend
the current thread and wait
for the start button to be pressed again. However whenever I hit stop it just suspends an waits for a second and resumes the counting. When in reality I want it to stay suspended. I'm not really sure why it's doing that, tried searching it before posting here but got nothing. Also feel free to criticize on anything you'd like.
Here's what I have:
UPDATED AS PER @MadProgrammer's answer.
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class main extends JFrame
{
JLabel countLabel = new JLabel("0");
JLabel statusLabel = new JLabel("Task not completed.");
JButton startButton = new JButton("Start");
JButton stopButton = new JButton("Stop");
CounterThread worker = new CounterThread("worker", countLabel, statusLabel);
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Main("Counter Demo");
}
});
}
public Main(String title) {
super(title);
setLayout(new GridBagLayout());
countLabel.setFont(new Font("serif", Font.BOLD, 28));
GridBagConstraints gc = new GridBagConstraints();
gc.fill = GridBagConstraints.NONE;
gc.gridx = 0;
gc.gridy = 0;
gc.weightx = 1;
gc.weighty = 1;
add(countLabel, gc);
gc.gridx = 0;
gc.gridy = 1;
gc.weightx = 1;
gc.weighty = 1;
add(statusLabel, gc);
gc.gridx = 0;
gc.gridy = 2;
gc.weightx = 1;
gc.weighty = 1;
add(startButton, gc);
gc.gridx = 0;
gc.gridy = 3;
gc.weightx = 1;
gc.weighty = 1;
add(stopButton, gc);
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
worker.start();
//notify();
}
});
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
worker.suspend();
}
});
setSize(200, 400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public class CounterThread implements Runnable {
public Thread t;
public String threadName;
boolean suspended = false;
JLabel countLabelName;
JLabel statusLabelName;
CounterThread(String name, JLabel cLabel, JLabel sLabel) {
this.threadName = name;
this.countLabelName = cLabel;
this.statusLabelName = sLabel;
}
public void run() {
try {
// Simulate doing something useful.
for (int i = 0; i <= 10; i++) {
synchronized (this) {
if (suspended)
{
wait();
}
}
final int count = i;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
countLabelName.setText(Integer.toString(count));
}
});
Thread.sleep(1000);
}
} catch (InterruptedException e) {
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
statusLabelName.setText("Completed.");
}
});
this.start();
}
public boolean getStatus() {
return t == null;
}
public void start() {
if (getStatus()) {
//t = new Thread(new CounterThread(this.threadName, this.countLabelName, this.statusLabelName));
t = new Thread(this);
t.start();
}
}
public void suspend() {
statusLabelName.setText("Task is paused");
suspended = true;
}
//create an object whose only purpose is to synchronize
synchronized void resume() {
statusLabelName.setText("Task has resumed");
suspended = false;
this.notify();
}
}
}
Basically...
getStatus
is returningfalse
so it's skipping thewait
call (becauset != null
.I'm not really sure why need to check this, but I might have a
enum
or other flag which returns a more meaningful state (likeRUNNING
,STOPPED
,PAUSED
... what ever)I was able to make it work by doing something like...
instead.
Having said that though. I'd personally consider using a Swing
Timer
which would do all this work for you and would trigger it's updates within the context of the EDTUpdated after original code was modified
You modified the code from the original post, adding
to the
start
method, but your UI code already has a reference toCounterThread
which it's interacting with, so now you have two instances of the same class, one which is running in the background ticking away and one which your UI code is interacting with.So when the UI calls
suspend
, it's not changing thesuspended
state of the instance which is actually runningThen you clearly don't understand how a
Timer
worksNow, there is the pause and resume issues all taken care off