如何等待java计时器完成
我有一个JavaSwingGUI,我试图在其中实现一个倒计时计时器。我有一系列任务,每个任务都需要在for循环中按顺序运行。我已经能够成功地使用swing定时器来执行倒计时,但是一旦我尝试将它放入循环中,我就无法在不冻结GUI的情况下更新它 这是我目前正在工作的一个SSCE。基本问题是这个示例并行运行三个30秒计时器。我想做的是按顺序运行三个30秒计时器,或者换句话说,它应该等待一个计时器完成,然后再开始下一个计时器。我尝试并等待计时器完成的所有操作都会使GUI冻结如何等待java计时器完成,java,multithreading,swing,timer,Java,Multithreading,Swing,Timer,我有一个JavaSwingGUI,我试图在其中实现一个倒计时计时器。我有一系列任务,每个任务都需要在for循环中按顺序运行。我已经能够成功地使用swing定时器来执行倒计时,但是一旦我尝试将它放入循环中,我就无法在不冻结GUI的情况下更新它 这是我目前正在工作的一个SSCE。基本问题是这个示例并行运行三个30秒计时器。我想做的是按顺序运行三个30秒计时器,或者换句话说,它应该等待一个计时器完成,然后再开始下一个计时器。我尝试并等待计时器完成的所有操作都会使GUI冻结 import java.aw
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.security.auth.callback.Callback;
import javax.swing.*;
public class SwingTester extends JFrame {
public SwingTester() {
JPanel panel = new JPanel();
getContentPane().add(panel);
panel.setLayout(new GridLayout(1,3));
setDefaultCloseOperation(EXIT_ON_CLOSE);
// Add the components
jLblTimer = new JLabel("00:30");
jLblSet = new JLabel("Set #1");
jBtnStart = new JButton("Start!");
jBtnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {jBtnStartActionPerformed(evt);}
});
// Add the labels
panel.add(jLblTimer); panel.add(jLblSet); panel.add(jBtnStart);
pack();
}
private void jBtnStartActionPerformed(ActionEvent evt) {
for (int ss=0; ss<3; ss++) {
// Change the set name
jLblSet.setText("Set #" + Integer.toString(ss+1));
// Setup the counter to begin the countdown
counter = 30;
timer = new Timer(1000, startCycle());
timer.start();
// I want to wait here until the timer is done, nothing I've done
// works without freezing the GUI.
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new SwingTester().setVisible(true);
}
});
}
private Action startCycle() {
return new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
new ClockTask(null).execute();
}
};
}
class ClockTask extends SwingWorker<Void, String> {
private Callback callback;
public ClockTask(Callback callback) {
this.callback = callback;
}
@Override
protected Void doInBackground() throws Exception {
if (counter >= 0) {
int millis = counter*1000;
String time = String.format("%02d:%02d", TimeUnit.MILLISECONDS.toMinutes(millis),
TimeUnit.MILLISECONDS.toSeconds(millis) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
);
publish(time); // call publish which will call process() method in EDT
counter--;
} else {
// this.callback.call();
this.callback.notify();
timer.stop();
}
return(null);
}
@Override
protected void process(List<String> times) {
String lastTime = times.get(times.size()-1);
jLblTimer.setText(lastTime); // just update ui with lastTimer, ohters are ignorable
}
@Override
protected void done() {
super.done();
}
// private interface Callback {
// void call();
// }
}
private javax.swing.JLabel jLblTimer;
private javax.swing.JLabel jLblSet;
private javax.swing.JButton jBtnStart;
private javax.swing.Timer timer;
private int counter;
}
import java.awt.*;
导入java.awt.event.*;
导入java.util.List;
导入java.util.concurrent.TimeUnit;
导入javax.security.auth.callback.callback;
导入javax.swing.*;
公共类SwingTester扩展了JFrame{
公共SwingTester(){
JPanel面板=新的JPanel();
getContentPane().add(面板);
面板设置布局(新网格布局(1,3));
setDefaultCloseOperation(关闭时退出);
//添加组件
jLblTimer=新JLabel(“00:30”);
jLblSet=新JLabel(“Set#1”);
jBtnStart=newjbutton(“Start!”);
jBtnStart.addActionListener(新ActionListener(){
public void actionPerformed(ActionEvent evt){jBtnStartActionPerformed(evt);}
});
//添加标签
panel.add(jLblTimer);panel.add(jlbset);panel.add(jBtnStart);
包装();
}
私有无效jBtnStartActionPerformed(ActionEvent evt){
对于(int ss=0;ss有几种方法。通常,您可以创建一个对象,将其传递给后台工作,在后台工作完成后,它使用该对象告诉您结果,并让您完成其余工作
private class ClockTask extends SwingWorker<Void, Void> {
private Callback _callback;
public ClockTask(Callback callback) {
this._callback = callback;
}
@Override
protected Void doInBackground() throws Exception {
if (counter >= 0) {
int millis = counter*1000;
String time = String.format("%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(millis),
TimeUnit.MILLISECONDS.toSeconds(millis) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
);
jLblTimer.setText(time);
counter--;
} else {
this._callback.notify();
}
return(null);
}
}
私有类ClockTask扩展SwingWorker{
私有回调(u Callback),;
公共时钟任务(回调){
这个._callback=callback;
}
@凌驾
受保护的Void doInBackground()引发异常{
如果(计数器>=0){
整数毫秒=计数器*1000;
字符串时间=字符串。格式(“%02d:%02d”,
时间单位。毫秒。至分钟(毫秒),
时间单位。毫秒。至秒(毫秒)——
时间单位:分钟到秒(时间单位:毫秒到分钟(毫秒))
);
jLblTimer.setText(时间);
计数器--;
}否则{
这是._callback.notify();
}
返回(空);
}
}
以下是您需要如何更换SwingWorker
class ClockTask extends SwingWorker<Void, String> {
private Callback callback;
public ClockTask(Callback callback) {
this.callback = callback;
}
@Override
protected Void doInBackground() throws Exception {
if (counter >= 0) {
int millis = counter*1000;
String time = String.format("%02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(millis),
TimeUnit.MILLISECONDS.toSeconds(millis) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
);
//jLblTimer.setText(time); // dont update UI in backgroudn thread
publish(time); // call publish which will call process() method in EDT
counter--;
} else {
this.callback.call();
}
return(null);
}
/*
* this method will be called in EDT and will not freeze your UI ;)
*/
@Override
protected void process(List<String> times) {
String lastTime = times.get(times.size()-1);
jLblTimer.setText(lastTime); // just update ui with lastTimer, ohters are ignorable
}
@Override
protected void done() {
super.done();
}
private interface Callback {
void call();
}
}
class ClockTask扩展SwingWorker{
私有回调;
公共时钟任务(回调){
this.callback=回调;
}
@凌驾
受保护的Void doInBackground()引发异常{
如果(计数器>=0){
整数毫秒=计数器*1000;
字符串时间=字符串。格式(“%02d:%02d”,
时间单位。毫秒。至分钟(毫秒),
时间单位。毫秒。至秒(毫秒)——
时间单位:分钟到秒(时间单位:毫秒到分钟(毫秒))
);
//jlbtimer.setText(time);//不要在后台线程中更新UI
publish(time);//调用publish,它将在EDT中调用process()方法
计数器--;
}否则{
this.callback.call();
}
返回(空);
}
/*
*此方法将在EDT中调用,并且不会冻结您的UI;)
*/
@凌驾
受保护的无效进程(列表次数){
字符串lastTime=times.get(times.size()-1);
setText(lastTime);//只需使用lastTimer更新ui,ohters是可忽略的
}
@凌驾
受保护的void done(){
超级。完成();
}
专用接口回调{
无效调用();
}
}
您应该多花点时间使用JavaDoc的“这是我的代码示例”以获得更好的帮助,请尽快发布。@AndrewThompson感谢您的建议。我犯了一个错误,刚刚有一个SE(简短的示例)。我已经更新了我的代码,使其成为SSCCE。运行时错误的SSCCE在编译时不会有16个错误。
(再次感谢@AndrewThompson。我忘了添加最后5行代码。它现在使用javac 1.7.0对我来说编译正常。这里显示了一个(奇数)倒计时,在以后的运行中似乎会更快。它应该做什么?-1用于更新标签(假设jlbTimer是一个JLabel)在后台线程中:SwingWorker的全部要点是干净地分离线程并管理与后台的通信-->EDT@jeffrey-赵,这可能是我的错误。我没有发布一个合适的SSCCE供你查看。我已经更新了我的代码,所以它是一个SSCCE,我仍然欢迎任何建议。@Kowser我找不到太多我需要的信息关于使用“私有回调”的信息;我已经编辑了我的代码以合并您的更改,谢谢。但是,它仍然在for循环中运行,没有停止,然后我似乎有3个计时器同时运行。我试图为您提供改进的解决方案,但从您的代码和最后的注释中很难理解(它仍然在for循环中运行,没有停止,然后我似乎有3个计时器同时运行
),这是您真正想要做的。@Kowser,再次感谢您抽出时间来帮助我。我正在尝试做的是jBtnStartActionPerformed()
函数在for循环中运行3次。每次循环中,倒计时计时器都应该启动,然后它应该等到它完成后再开始下一个倒计时计时器。现在它不会等到计时器完成,我似乎不知道如何在不冻结GUI的情况下执行此操作。嗨,我试图研究代码,我试着编译它,但它至少出现了10个错误,并且无法解决这些问题:(我不是要完整的代码,但至少是一些可以编译的东西,或者至少是一些与