秒表取消暂停功能无效 [英] Stopwatch unpause doesn't work
问题描述
我正在尝试制作秒表。 开始和暂停按钮可以正常工作,但取消暂停按钮无法正常工作。
timer 是我的JLabel,我想在其中显示秒表(它引用了JFrame中的 timer )。我无法发布MCVE,因为它的代码太多。
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.
这是我的秒表课程:
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);
推荐答案
您需要某种方式来暂停 Thread
并停止进行更新。您可以在 run
循环中使用 if
语句来执行此操作,但是可以通过使用监视锁
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();
}
}
}
现在,我们有更大的问题是,Swing不是线程安全的。这意味着您的 update
方法违反了Swing的单线程规则,可能不会导致问题的结束。
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...
一个更简单的解决方案是只使用Swing Timer
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));
}
}
}
}
有关更多详细信息,请参见如何使用Swing计时器
See How to use Swing Timers for more details
这篇关于秒表取消暂停功能无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!