JFrame时间输出、计时器

利用JFrame实现时间输出和计时器功能,输出当前时间XXXX年XX月XX日  xx时xx分xx秒。秒表,可以开始计时,暂停,继续计时和清零的功能。功能虽然简单,但挺好玩的。做的时候没有加入大量其他的设计让外观变的好看,感兴趣的还可以往上面加其他功能。

这个大概是半年前弄的小玩意,当时没有接触到博客,最近在整理代码时无意间发现,觉得挺有意思的,拿出来给自己总结一下。

唯一碰到的坑就是这两个东西分开时都能正常,当合并在一起时,线程之间会发生冲突,时间错乱,当时想了很久没有想到,后来真正接触到了守护线程,内部类的时候,定义了守护线程,定义了内部类,将冲突的线程给分离开,最终实现了

效果图如下

JFrame时间输出、计时器_第1张图片

先说说思路,两个lable,一个显示当前时间,一个显示开始计时的时间。一共两个按钮,开始和清零,给这两个按钮设置监听器,并且设置一个状态,状态默认是暂停的,在开始按钮的监听事件中判断。当为true时按钮显示为继续,当点击后状态改变为false,按钮显示为暂停。调用对应的线程处理不同的事情。

主要讲那个设置的状态理解透那就不难了,定义一个stopped状态

//计时器初始状态是暂停的
	 private long pauseStart=progranStart;

是否开始或者继续计时都是由该状态决定,进入计时器线程后,状态值设置为true。当进入到监听器时,判断状态值,为true则开始计时,每毫秒刷新一次,并将状态改变为false,按钮显示为暂停,当点击暂停时,状态变成true,计时停止,按钮变成继续。这里比较容易混乱建议拿着代码多敲几遍理解一下。

清零按钮的监听器事件设置,就是将lable中的初始值00:00:00 000还原,将状态变成true。

而时间显示线程写成外部类,避免与时间计时线程相冲突。再有线程去调用,每秒刷新一次。

代码里面都有注释

代码如下:

package time;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 * 
 * @author wlw
 *
 */
public class time extends JFrame {
	/**
	 * 序列化
	 */
	private static final long serialVersionUID = 4408196785766662795L;
	// 初始显示
	private static final String INITIAL_LABEL_TEXT = "00:00:00 000";
	// 计数线程 内部类
	private CountingThread thread = new CountingThread();
	// 计时器开始时间
	private long progranStart = System.currentTimeMillis();
	// 计时器初始状态是暂停的
	private long pauseStart = progranStart;
	// 计时器暂停时的时间
	private long pauseCount = 0;
	static JLabel lable2 = new JLabel(INITIAL_LABEL_TEXT);
	static JButton startPanuseButton = new JButton("开始");
	static JButton resetButtone = new JButton("清零");
	/**
	 * 暂停或者继续的监听器
	 * 
	 */
	private ActionListener startPauseButtonListener = new ActionListener() {
		@Override
		public void actionPerformed(ActionEvent e) {
			if (thread.stopped) {
				// 暂停的时间=开始的时间-暂停时的总时间+暂停的时间
				pauseCount += (System.currentTimeMillis() - pauseStart);
				thread.stopped = false; // 停止计数线程运行
				startPanuseButton.setText("暂停");// 将开始按钮变成暂停按钮
			} else {
				pauseStart = System.currentTimeMillis();
				thread.stopped = true;
				startPanuseButton.setText("继续");
			}

		}
	};
	// 定义一个侦听器,点击清零时触发
	private ActionListener resetButtonList = new ActionListener() {

		@Override
		public void actionPerformed(ActionEvent e) {
			pauseStart = progranStart; // 开始计时
			pauseCount = 0; // 暂停的时间清零
			thread.stopped = true;// 启动计时线程
			lable2.setText(INITIAL_LABEL_TEXT);// 00:00:00
			startPanuseButton.setText("开始");
		}
	};

	/**
	 * 定义个一内部类:计算线程,计算总的时间
	 * 
	 * @author soft01
	 *
	 */
	// 计时器线程
	class CountingThread extends Thread {
		/**
		 * 定义一个状态,判断是否是(暂停、继续)计时
		 */
		public boolean stopped = true;

		private CountingThread() {
			/**
			 * 定义守护线程(主线程结束时,守护线程死亡)
			 */
			setDaemon(true);
		}

		@Override
		public void run() {
			while (true) {
				if (!stopped) {
					// 减去开始的时间减去暂停的时间
					long elapsed = System.currentTimeMillis() - progranStart - pauseCount;
					lable2.setText(Format(elapsed));
				}
				try {
					sleep(1);// 每一毫秒就刷新一次
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					// System.exit(0);正常退出,程序正常执行结束退出
					// 如果非正常退出,就是说无论程序正在执行与否,都退出
					System.exit(1);
				}
			}
		}
          /时间转换的方法   将每次刷新的值,换成时,分,秒,毫秒
		private String Format(long elapsed) {
			int hour, minute, second, milli;// 定义时,分,妙,毫秒
			milli = (int) (elapsed % 1000);
			elapsed = elapsed / 1000;

			second = (int) (elapsed % 60);
			elapsed = elapsed / 60;

			minute = (int) (elapsed % 60);
			elapsed = elapsed / 60;

			hour = (int) (elapsed % 60);
			// %02d:%02d:%02d:%03d 00:00:00:000
			return String.format("%02d:%02d:%02d:%03d", hour, minute, second, milli);
		}
	}

	// 构造方法
	public time(String title) {
		super(title);
		// 对开始、暂停按钮进行侦听
		startPanuseButton.addActionListener(startPauseButtonListener);
		// 对清零按钮进行侦听
		resetButtone.addActionListener(resetButtonList);
		// 启动计数线程
		thread.start();
	}

	public static void main(String[] args) throws InterruptedException {
		time frame = new time("时间");
		JPanel panel = new JPanel();
		Font font = new Font("宋体", Font.BOLD, 30);
		/**
		 * 调用时间类,输出当前时间
		 */
		Timerto timer = new Timerto();
		/**
		 * 系统时间线程
		 */
		Thread th = new Thread(timer);
		th.start();
		JLabel lable = new JLabel();

		// try {
		// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		// } catch (Exception e) {
		// // TODO: handle exception
		// }

		panel.setLayout(null);// 打破面板的默认布局,只有这样标签才能移动
		panel.setBackground(Color.red);
		lable.setBackground(Color.yellow);
		lable.setFont(font);
		lable.setOpaque(true);// 打破标签的默认布局
		lable.setBounds(200, 60, 330, 60); // 设置标签的位置
		lable2.setBackground(Color.yellow);
		lable2.setFont(font);
		lable2.setOpaque(true);// 打破标签的默认布局
		lable2.setBounds(200, 180, 330, 60);
		startPanuseButton.setBounds(200, 280, 90, 60);
		resetButtone.setBounds(400, 280, 90, 60);
		panel.add(startPanuseButton);
		panel.add(resetButtone);
		panel.add(lable); // 把标签贴到面板上
		panel.add(lable2);
		frame.add(panel); // 将面板插入到窗口中去
		frame.setSize(800, 400); // 设置窗口的宽高
		frame.setLocationRelativeTo(null);// 设置窗口默认中间
		frame.setAlwaysOnTop(true);// 设置窗口永远显示在最前端
		frame.setResizable(false);// 设置窗口不能被修改
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
		// frame.pack();
		/**
		 * 不断刷新当前时间
		 */
		while (true) {
			lable.setText(timer.getCurrentTime());
		}
	}

}

/**
 * 定义一个Timerto类,继承Runnable 输出现在的时间
 * 
 * @author wlw
 *
 */
class Timerto implements Runnable {
	private String currentTime;

	// 获取当前时间
	public String getCurrentTime() {
		Date d = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		currentTime = sdf.format(d);
		return currentTime;
	}

	/**
	 * 每秒刷新一次
	 */
	public void run() {
		try {
			Thread.sleep(1000);
			getCurrentTime();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

 

 

 

 

 

你可能感兴趣的:(JFrame,Time,JFrame,JAVA实现计时器,JAVA输出当前时间,秒表)