Java 计时器/秒表GUI
我正在尝试制作一个简单的java应用程序,它可以计算时间,并能够停止和启动计时器。但是,标签不会更新,当我按start时,它会冻结 你能帮我找出问题所在吗Java 计时器/秒表GUI,java,swing,user-interface,timer,Java,Swing,User Interface,Timer,我正在尝试制作一个简单的java应用程序,它可以计算时间,并能够停止和启动计时器。但是,标签不会更新,当我按start时,它会冻结 你能帮我找出问题所在吗 package random; import javax.swing.JFrame; public class Timer { boolean shouldCount=false; int int_sec=0; int int_min=0; int int_mil=0; public static void main(String[] a
package random;
import javax.swing.JFrame;
public class Timer {
boolean shouldCount=false;
int int_sec=0;
int int_min=0;
int int_mil=0;
public static void main(String[] args) {
TimeFrame t = new TimeFrame();
JFrame f = new JFrame("Timer");
f.setSize(300,200);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.getContentPane().add(t);
f.setVisible(true);
}
public void count(){
TimeFrame t = new TimeFrame();
if(shouldCount){
long now = System.currentTimeMillis();
while(true){
if(System.currentTimeMillis()-now>=100){
now=System.currentTimeMillis();
String sec = Integer.toString(int_sec);
String min = Integer.toString(int_min);
String mil = Integer.toString(int_mil);
t.update(sec,int_sec,min,mil,int_mil);
int_mil++;
if(int_mil>9){
int_mil=0;
int_sec++;
if(int_sec>=60){
int_sec=1;
int_min++;
}
}
}
}
}
}
}
这里是TimeFrame.java package random;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TimeFrame extends JPanel{
JLabel time = new JLabel("Time goes here", JLabel.CENTER);
Timer t = new Timer();
JButton pause = new JButton ("Pause");
JButton start = new JButton ("Start");
public TimeFrame(){
start.addActionListener(new starts());
pause.addActionListener(new starts());
add(time);
add(start);
add(pause);
}
public void update(String sec,int s, String min,String mil,int m){
if (s<=10){
sec="0"+sec;
}
System.out.println(min+":"+sec+","+mil);
time.setText(min+":"+sec+","+mil);
}
public class starts implements ActionListener{
public void actionPerformed(ActionEvent event){
if(event.getSource() == start){
t.shouldCount=true;
}else{
t.shouldCount=false;
}
t.count();
}
}
}
随机包装;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入javax.swing.JButton;
导入javax.swing.JLabel;
导入javax.swing.JPanel;
公共类时间框架扩展了JPanel{
JLabel time=newjlabel(“时间在这里”,JLabel.CENTER);
定时器t=新定时器();
JButton pause=新JButton(“暂停”);
JButton start=新JButton(“start”);
公共时间表(){
addActionListener(newstarts());
pause.addActionListener(newstarts());
加上(时间);
添加(开始);
添加(暂停);
}
公共无效更新(字符串秒、整数s、字符串最小值、字符串mil、整数m){
如果(s问题是应用程序中只有一个线程,那么至少应该有两个线程:一个用于更新文本的UI,另一个用于计算时间
如果只有一个线程,它将挂起在while(true)循环中,Swing永远无法更新视图
我使用两个线程重构了您的代码:
一次计数直到时间结束,并更新字段以将时间保留在内存中
另一个是使用java.util.Timer#scheduleAtFixedRate()方法的,该方法每100毫秒调用一次以更新视图
Timer.java
(避免像JavaAPI中那样命名类)
TimeFrame
(我更愿意称之为TimePanel
,因为它扩展了JPanel
)
公共类时间框架扩展JPanel{
JLabel时间;
定时器t;
按钮暂停;
按钮启动;
公共时间表(){
t=新计时器(此);
时间=新的JLabel(“时间在这里”,JLabel.CENTER);
暂停=新按钮(“暂停”);
开始=新的JButton(“开始”);
addActionListener(newstarts());
pause.addActionListener(newstarts());
加上(时间);
添加(开始);
添加(暂停);
java.util.Timer updateTimer=new java.util.Timer();
updateTimer.scheduleAtFixedRate(新TimerTask(){
@凌驾
公开募捐{
t、 更新(单位秒、单位分钟、单位英里);
}
}, 0, 100);
}
公共无效更新(整数s、整数分钟、整数m){
字符串秒=整数。toString(s);
字符串最小值=整数。toString(分钟);
字符串mil=整数。toString(m);
如果(s问题在于while循环绑定到接口线程。当您单击开始按钮时,它调用Timer.count(),然后进入无限循环,导致接口被卡住,永远不会更新
使用java.util.Timer类更好的假设可能高估了该类针对此特定问题的功能。它不包含暂停方法,您必须在想要暂停计时器时重新创建计时器,这可能会给时间加总带来一些困难
我要做的是让你的计时器实现runnable接口,并使用一个线程来记录你当前的时间
请注意,我将字段设置为私有。将字段设置为私有(如果应该的话)并使用getter和setter授予对它们的访问权限是正确的做法。例如:getCurrentTime()
Timer.java:
package random;
import javax.swing.JFrame;
public class Timer implements Runnable {
private Thread runThread;
private boolean running = false;
private boolean paused = false;
private TimeFrame timeFrame;
private long summedTime = 0;
public Timer(TimeFrame timeFrame) {
this.timeFrame = timeFrame;
}
public static void main(String[] args) {
TimeFrame t = new TimeFrame();
JFrame f = new JFrame("Timer");
f.setSize(300,200);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.getContentPane().add(t);
f.setVisible(true);
}
public void startTimer() {
running = true;
paused = false;
// start the thread up
runThread = new Thread(this);
runThread.start();
}
public void pauseTimer() {
// just pause it
paused = true;
}
public void stopTimer() {
// completely stop the timer
running = false;
paused = false;
}
@Override
public void run() {
long startTime = System.currentTimeMillis();
// keep showing the difference in time until we are either paused or not running anymore
while(running && !paused) {
timeFrame.update(summedTime + (System.currentTimeMillis() - startTime));
}
// if we just want to pause the timer dont throw away the change in time, instead store it
if(paused)
summedTime += System.currentTimeMillis() - startTime;
else
summedTime = 0;
}
}
TimeFrame.java:
package random;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TimeFrame extends JPanel{
private JLabel time = new JLabel("Time goes here", JLabel.CENTER);
private Timer timer;
private JButton pause = new JButton ("Pause");
private JButton start = new JButton ("Start");
public TimeFrame(){
timer = new Timer(this);
start.addActionListener(new starts());
pause.addActionListener(new starts());
add(time);
add(start);
add(pause);
}
public void update(long dT){
// convert milliseconds into other forms
time.setText(String.valueOf((dT/6000)%1000)+":"+String.valueOf((dT/1000)%1000)+","+String.valueOf((dT)%1000));
}
public class starts implements ActionListener{
public void actionPerformed(ActionEvent event){
if(event.getSource() == start){
timer.startTimer();
}else{
timer.pauseTimer();
}
}
}
}
为什么不使用a而不是while
循环?另外,您可能正试图从另一个线程更新gui线程,这将导致问题。我认为存在runLater()
thread thing,可以让您从其他线程安全地更新gui线程。谢谢,除了暂停按钮外,它工作得很好。我读了代码,我认为它可以工作,但它没有,你知道为什么吗?是的,要使它工作,有一些事情需要更改。我会研究它,但你也可以在设置“应该计数”时自己尝试如果设置为true或false,则不会影响while true循环,因为从未计算该条件。请将该条件放入while循环中,并从ActionListener中删除t.count(),因为它将创建一个新线程。
package random;
import javax.swing.JFrame;
public class Timer implements Runnable {
private Thread runThread;
private boolean running = false;
private boolean paused = false;
private TimeFrame timeFrame;
private long summedTime = 0;
public Timer(TimeFrame timeFrame) {
this.timeFrame = timeFrame;
}
public static void main(String[] args) {
TimeFrame t = new TimeFrame();
JFrame f = new JFrame("Timer");
f.setSize(300,200);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.getContentPane().add(t);
f.setVisible(true);
}
public void startTimer() {
running = true;
paused = false;
// start the thread up
runThread = new Thread(this);
runThread.start();
}
public void pauseTimer() {
// just pause it
paused = true;
}
public void stopTimer() {
// completely stop the timer
running = false;
paused = false;
}
@Override
public void run() {
long startTime = System.currentTimeMillis();
// keep showing the difference in time until we are either paused or not running anymore
while(running && !paused) {
timeFrame.update(summedTime + (System.currentTimeMillis() - startTime));
}
// if we just want to pause the timer dont throw away the change in time, instead store it
if(paused)
summedTime += System.currentTimeMillis() - startTime;
else
summedTime = 0;
}
}
package random;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TimeFrame extends JPanel{
private JLabel time = new JLabel("Time goes here", JLabel.CENTER);
private Timer timer;
private JButton pause = new JButton ("Pause");
private JButton start = new JButton ("Start");
public TimeFrame(){
timer = new Timer(this);
start.addActionListener(new starts());
pause.addActionListener(new starts());
add(time);
add(start);
add(pause);
}
public void update(long dT){
// convert milliseconds into other forms
time.setText(String.valueOf((dT/6000)%1000)+":"+String.valueOf((dT/1000)%1000)+","+String.valueOf((dT)%1000));
}
public class starts implements ActionListener{
public void actionPerformed(ActionEvent event){
if(event.getSource() == start){
timer.startTimer();
}else{
timer.pauseTimer();
}
}
}
}