问题
I'm trying to create a stopwatch. The start and pause buttons works fine but the unpause button doesn't work properly. timer is my JLabel in which I want to ilustrate my stopwatch (it references timer from the JFrame). I can't post a MCVE because it's too much code.
Here is my Stopwatch class:
public class Stopwatch extends Thread {
private boolean finishedFlag = false;
private boolean pauseFlag = false;
private boolean sortFlag = false;
private long summedTime = 0;
private JLabel timer;
public Stopwatch(){}
public Stopwatch(boolean finished, boolean pause, boolean sort, JLabel timer){
this.finishedFlag = finished;
this.pauseFlag = pause;
this.sortFlag = sort;
this.timer = timer;
}
@Override
public void run() {
long startTime = System.currentTimeMillis();
while(sortFlag && !pauseFlag && !finishedFlag) {
update(summedTime + (System.currentTimeMillis() - startTime));
}
if(pauseFlag)
summedTime += System.currentTimeMillis() - startTime;
else
summedTime = 0;
}
private void update(long dT){
long x = (dT/1000)%60;
long y = (dT/60000)%1000;
if(x>=0 && x<=9 && y>=0 && y<=9)
timer.setText("0"+String.valueOf((dT/60000)%1000)+":0"+String.valueOf((dT/1000)%60)+","+String.valueOf((dT)%1000));
else if(x>9 && y>=0 && y<=9)
timer.setText("0"+String.valueOf((dT/60000)%1000)+":"+String.valueOf((dT/1000)%60)+","+String.valueOf((dT)%1000));
else if(x>=0 && x<=9 && y>9)
timer.setText(String.valueOf((dT/60000)%1000)+":0"+String.valueOf((dT/1000)%60)+","+String.valueOf((dT)%1000));
else if(x>9 && y>9)
timer.setText(String.valueOf((dT/60000)%1000)+":"+String.valueOf((dT/1000)%60)+","+String.valueOf((dT)%1000));
}
}
This are the listeners I use for my buttons:
ActionListener sortListener = new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
if(sortFlag == false && pauseFlag == false)
{
sortFlag = true;
System.out.println("sort");
stopwatch1 = new Stopwatch(finishedFlag,pauseFlag,sortFlag,timer1);
stopwatch1.start();
appFrame.validate();
appFrame.repaint();
}
}
};
sortButton.addActionListener(sortListener);
ActionListener pauseListener = new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
if(sortFlag && pauseFlag == false)
{
pauseFlag = true;
timeSpent = stopwatch1.getSummedTime();
stopwatch1.setPauseFlag(true);
System.out.println("pause");
}
}
};
pauseButton.addActionListener(pauseListener);
ActionListener unpauseListener = new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
if(sortFlag && pauseFlag)
{
pauseFlag = false;
stopwatch1.setPauseFlag(false);
stopwatch1.run();
System.out.println("unpause");
}
}
};
unpauseButton.addActionListener(unpauseListener);
回答1:
You need someway to pause the Thread and stop the update from occurring. You could do this with an if statement inside your run loop, but there is a more efficient way through the use of monitor lock
public class Stopwatch extends Thread {
//...
private final Object pauseLock;
public Stopwatch() {
pauseLock = new Object();
}
public Stopwatch(boolean finished, boolean pause, boolean sort, JLabel timer) {
this();
//...
}
@Override
public void run() {
long startTime = System.currentTimeMillis();
while (sortFlag && !finishedFlag) {
while (pauseFlag) {
synchronized (pauseLock) {
try {
pauseLock.wait();
} catch (InterruptedException ex) {
}
}
}
update(summedTime + (System.currentTimeMillis() - startTime));
}
if (pauseFlag) {
summedTime += System.currentTimeMillis() - startTime;
} else {
summedTime = 0;
}
}
Now, you need some way to pause and resume the run loop
public void setPaused(boolean paused) {
if (paused && !pauseFlag) {
pauseFlag = paused;
} else if (!paused && pauseFlag) {
pauseFlag = paused;
synchronized (pauseLock) {
pauseLock.notifyAll();
}
}
}
Now, however, we have bigger problem, Swing is NOT thread safe. This means that your update method is breaking the single thread rules of Swing and could cause no end of issues...
A simpler solution would be to just use a Swing Timer
import java.awt.EventQueue;
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 javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label;
private StopWatch sw;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
label = new JLabel("...");
add(label, gbc);
sw = new StopWatch(label);
JButton btn = new JButton("Resume");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
sw.setPaused(!sw.isPaused());
btn.setText(sw.isPaused() ? "Resume" : "Pause");
}
});
add(btn, gbc);
}
}
public class StopWatch {
private Timer timer;
private JLabel label;
private int runningTime;
private long tickTime;
public StopWatch(JLabel label) {
this.label = label;
timer = new Timer(10, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
runningTime += (System.currentTimeMillis() - tickTime);
System.out.println(runningTime);
update(runningTime);
tickTime = System.currentTimeMillis();
}
});
}
public void setPaused(boolean paused) {
if (paused && timer.isRunning()) {
timer.stop();
} else if (!paused && !timer.isRunning()) {
tickTime = System.currentTimeMillis();
timer.start();
}
}
public boolean isPaused() {
return !timer.isRunning();
}
private void update(long dT) {
long x = (dT / 1000) % 60;
long y = (dT / 60000) % 1000;
if (x >= 0 && x <= 9 && y >= 0 && y <= 9) {
label.setText("0" + String.valueOf((dT / 60000) % 1000) + ":0" + String.valueOf((dT / 1000) % 60) + "," + String.valueOf((dT) % 1000));
} else if (x > 9 && y >= 0 && y <= 9) {
label.setText("0" + String.valueOf((dT / 60000) % 1000) + ":" + String.valueOf((dT / 1000) % 60) + "," + String.valueOf((dT) % 1000));
} else if (x >= 0 && x <= 9 && y > 9) {
label.setText(String.valueOf((dT / 60000) % 1000) + ":0" + String.valueOf((dT / 1000) % 60) + "," + String.valueOf((dT) % 1000));
} else if (x > 9 && y > 9) {
label.setText(String.valueOf((dT / 60000) % 1000) + ":" + String.valueOf((dT / 1000) % 60) + "," + String.valueOf((dT) % 1000));
}
}
}
}
See How to use Swing Timers for more details
来源:https://stackoverflow.com/questions/29596286/stopwatch-unpause-doesnt-work