定时器/秒表GUI

时间:2013-09-20 22:32:24

标签: java swing user-interface timer

我正在尝试创建一个简单的Java应用程序来计算时间,能够停止并启动计时器。但是,标签不会更新,当我按下开始时,它会冻结。

你能帮我弄清问题是什么吗?

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();
        }
    }
}

2 个答案:

答案 0 :(得分:3)

问题是您的应用程序中只有一个线程。您应该至少有两个:一个用于更新文本的UI,另一个用于计算时间。

如果你只有一个线程挂在while(true)循环中,Swing永远不会更新视图。

我使用两个线程重构了你的代码:

  1. 一直计算到时间结束并更新字段以留出时间

  2. 另一个使用java.util.Timer#scheduleAtFixedRate()方法的方法,每100毫秒更新一次以更新视图。

  3. Timer.java(避免命名类似Java API中的类)

        public class Timer {
    
            boolean shouldCount=false;
            int int_sec=0;
            int int_min=0;
            int int_mil=0;
    
            public Timer() {
            }
    
            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(new TimeFrame());
                f.setVisible(true);
            }
    
            public void count(){
                    Thread thread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            long now = System.currentTimeMillis();
                            while(true){
                            if(shouldCount){
                                if(System.currentTimeMillis()-now>=100){
                                    now=System.currentTimeMillis();
                                    int_mil++;
                                    if(int_mil>9){
                                         int_mil=0;
                                         int_sec++;
                                         if(int_sec>=60){
                                              int_sec=1;
                                              int_min++;
                                         }
                                    }
                                }       
                            }
                        }               
                    }
                });
                thread.start();
            }
        }
    }
    

    TimeFrame(我宁愿称之为TimePanel,因为它扩展了JPanel

    public class TimeFrame extends JPanel{
        JLabel time;
        Timer t ;
        JButton pause ;
        JButton start ;
        public TimeFrame(){
    
            t= new Timer(this);
    
            time = new JLabel("Time goes here", JLabel.CENTER);
            pause = new JButton ("Pause");
            start = new JButton ("Start");
    
            start.addActionListener(new starts());
            pause.addActionListener(new starts());
            add(time);
            add(start);
            add(pause);
    
            java.util.Timer updateTimer= new java.util.Timer();
            updateTimer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                t.update(int_sec,int_min,int_mil);
            }
            }, 0, 100);
        }    
    
        public void update(int s, int minute,int m){
            String sec = Integer.toString(s);
            String min = Integer.toString(minute);
            String mil = Integer.toString(m);
        if (s<=10){
                sec="0"+sec;
            }
    
            System.out.println(min+":"+sec+","+mil);
            time.setText(min+":"+sec+","+mil);
        }
    
    
       public class starts implements ActionListener{
        boolean firstTime=true;
        public void actionPerformed(ActionEvent event){
            if (firstTime){
                t.count();
                firstTime = false;
            }
            if(event.getSource() == start){
                t.shouldCount=true;
            }else{
                t.shouldCount=false;
            }
        }
    }
    
    }
    

答案 1 :(得分:1)

问题是你的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();
            }
        }
    }
}