我试图制作一个秒表。 开始和暂停按钮工作正常但取消暂停按钮无法正常工作。 计时器是我的JLabel,其中我想说明我的秒表(它从JFrame引用计时器)。我无法发布MCVE,因为它的代码太多了。
这是我的秒表类:
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));
}
}
这是我用于按钮的听众:
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);
答案 0 :(得分:2)
您需要暂停Thread
并停止更新。您可以在if
循环内使用run
语句执行此操作,但使用监视锁定有一种更有效的方法
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;
}
}
现在,您需要一些方法来暂停和恢复run
循环
public void setPaused(boolean paused) {
if (paused && !pauseFlag) {
pauseFlag = paused;
} else if (!paused && pauseFlag) {
pauseFlag = paused;
synchronized (pauseLock) {
pauseLock.notifyAll();
}
}
}
但是,现在我们遇到了更大的问题,Swing不是线程安全的。这意味着您的update
方法违反了Swing的单线程规则,并且可能导致问题无法结束......
更简单的解决方案是使用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));
}
}
}
}
有关详细信息,请参阅How to use Swing Timers