Java 小例子:简单秒表

这是一个简单的秒表。看起来很简单,但是这里有一个设计上的问题。一般初学者会创建一个循环的线程讲一个整数叠加,该线程隔一段时间暂停一下,比如暂停 10 毫秒,然后往这个整数上加 10。

这样设计的问题在于,线程的暂停和继续,以及计数和显示都是要花费时间的。所以这样的程序运行越久,误差就会越大。下面这个例子就是经过改良的,能够将时间误差维持在极低的水平上。

Code:
  1. import javax.swing.*;  
  2. import java.awt.HeadlessException;  
  3. import java.awt.BorderLayout;  
  4. import java.awt.FlowLayout;  
  5. import java.awt.Font;  
  6. import java.awt.event.ActionListener;  
  7. import java.awt.event.ActionEvent;  
  8.    
  9. /** 
  10.  * 小小的计时器 
  11.  */  
  12. public class TimerFrame extends JFrame {  
  13.    
  14.     private static final String INITIAL_LABEL_TEXT = "00:00:00 000";  
  15.    
  16.     // 计数线程  
  17.     private CountingThread thread = new CountingThread();  
  18.    
  19.     // 记录程序开始时间  
  20.     private long programStart = System.currentTimeMillis();  
  21.    
  22.     // 程序一开始就是暂停的  
  23.     private long pauseStart = programStart;  
  24.    
  25.     // 程序暂停的总时间  
  26.     private long pauseCount = 0;  
  27.    
  28.     private JLabel label = new JLabel(INITIAL_LABEL_TEXT);  
  29.    
  30.     private JButton startPauseButton = new JButton("开始");  
  31.    
  32.     private JButton resetButton = new JButton("清零");  
  33.    
  34.     private ActionListener startPauseButtonListener = new ActionListener() {  
  35.         public void actionPerformed(ActionEvent e) {  
  36.             if (thread.stopped) {  
  37.                 pauseCount += (System.currentTimeMillis() - pauseStart);  
  38.                 thread.stopped = false;  
  39.                 startPauseButton.setText("暂停");  
  40.             } else {  
  41.                 pauseStart = System.currentTimeMillis();  
  42.                 thread.stopped = true;  
  43.                 startPauseButton.setText("继续");  
  44.             }  
  45.         }  
  46.     };  
  47.    
  48.     private ActionListener resetButtonListener = new ActionListener() {  
  49.         public void actionPerformed(ActionEvent e) {  
  50.             pauseStart = programStart;  
  51.             pauseCount = 0;  
  52.             thread.stopped = true;  
  53.             label.setText(INITIAL_LABEL_TEXT);  
  54.             startPauseButton.setText("开始");  
  55.         }  
  56.     };  
  57.    
  58.     public TimerFrame(String title) throws HeadlessException {  
  59.         super(title);  
  60.         setDefaultCloseOperation(EXIT_ON_CLOSE);  
  61.         setLocation(200200);  
  62.         setResizable(false);  
  63.    
  64.         setupBorder();  
  65.         setupLabel();  
  66.         setupButtonsPanel();  
  67.    
  68.         startPauseButton.addActionListener(startPauseButtonListener);  
  69.         resetButton.addActionListener(resetButtonListener);  
  70.    
  71.         thread.start(); // 计数线程一直就运行着  
  72.     }  
  73.    
  74.     // 为窗体面板添加边框  
  75.     private void setupBorder() {  
  76.         JPanel contentPane = new JPanel(new BorderLayout());  
  77.         contentPane.setBorder(BorderFactory.createEmptyBorder(5555));  
  78.         this.setContentPane(contentPane);  
  79.     }  
  80.    
  81.     // 配置按钮  
  82.     private void setupButtonsPanel() {  
  83.         JPanel panel = new JPanel(new FlowLayout());  
  84.         panel.add(startPauseButton);  
  85.         panel.add(resetButton);  
  86.         add(panel, BorderLayout.SOUTH);  
  87.     }  
  88.    
  89.     // 配置标签  
  90.     private void setupLabel() {  
  91.         label.setHorizontalAlignment(SwingConstants.CENTER);  
  92.         label.setFont(new Font(label.getFont().getName(), label.getFont().getStyle(), 40));  
  93.         this.add(label, BorderLayout.CENTER);  
  94.     }  
  95.    
  96.     // 程序入口  
  97.     public static void main(String[] args) {  
  98.         try {  
  99.             UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());  
  100.         } catch (Exception e) {  
  101.             e.printStackTrace();  
  102.         }  
  103.    
  104.         TimerFrame frame = new TimerFrame("小小计时器");  
  105.         frame.pack();  
  106.         frame.setVisible(true);  
  107.     }  
  108.    
  109.     private class CountingThread extends Thread {  
  110.    
  111.         public boolean stopped = true;  
  112.    
  113.         private CountingThread() {  
  114.             setDaemon(true);  
  115.         }  
  116.    
  117.         @Override  
  118.         public void run() {  
  119.             while (true) {  
  120.                 if (!stopped) {  
  121.                     long elapsed = System.currentTimeMillis() - programStart - pauseCount;  
  122.                     label.setText(format(elapsed));  
  123.                 }  
  124.    
  125.                 try {  
  126.                     sleep(17);  // 使时钟显得更乱  
  127.                 } catch (InterruptedException e) {  
  128.                     e.printStackTrace();  
  129.                     System.exit(1);  
  130.                 }  
  131.             }  
  132.         }  
  133.    
  134.         // 将毫秒数格式化  
  135.         private String format(long elapsed) {  
  136.             int hour, minute, second, milli;  
  137.    
  138.             milli = (int) (elapsed % 1000);  
  139.             elapsed = elapsed / 1000;  
  140.    
  141.             second = (int) (elapsed % 60);  
  142.             elapsed = elapsed / 60;  
  143.    
  144.             minute = (int) (elapsed % 60);  
  145.             elapsed = elapsed / 60;  
  146.    
  147.             hour = (int) (elapsed % 60);  
  148.    
  149.             return String.format("%02d:%02d:%02d %03d", hour, minute, second, milli);  
  150.         }  
  151.     }  
  152. }  

 

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值