2013.09.17
Timer类的使用
这次我们要讲的是TimerTask类和Timer类的使用。
说道TimerTask类,与Thread类有相似之处,都是实现了Runnable接口,继承后要重写run方法,
在run方法里,我们要写内容其实是相同的,不同之处在于Thread里实现Runnable接口往往需要先进行一个死循环,或者用一个休止符控制这个循环,在循环里我们写入要一直实现的方法,然后每次循环即将结束时对线程进行一个休眠。而TimerTask类则有点不同,这个类不用进行死循环和每次循环的休眠,定义后,线程会自动地按一定周期性的运行。
首先我们是继承类TimerTask,然后我们就是要new一个Timer对象,Timer有一个方法,就是schedule(TimerTask task,long delay,long period);其中delay是指运行线程的时间,peroid是运行周期。
只要在主函数,监听器或者线程里进行计划,其中传入你要进行的TimerTask类,就可以实现线程的运行了。
今天我们要做的是一个定时闹钟:
我们来分析一下闹钟所需要实现的功能:
1、一个时钟:能够时刻提示现在的时间,方便我们设计闹钟
2、定时:能够在一个固定的时间点进行响铃
3、自定义声音文件:我们往往希望每次响用不同的声音
4、闹钟的存储:订一次以后就不需要再重复地订了
首先我们做一个界面
然后我们要让上面的时钟显示具体的时间:
/**
* 时间面板的设定
*
* @param jtf
*/
public void getTime(JTextField jtf) {
ClockTimer ct = new ClockTimer(jtf, 0);// 实例化ClockTimer对象
Timer t = new Timer();// 创建Timer对象
t.schedule(ct, 50, 50);// 开启线程
}
然后我们写监听器的类:
public class ClockListener implements ActionListener {
String path = null;// 声音文件路径
JComboBox jcbhour;// 小时的下拉框
JComboBox jcbmin;// 分钟的下拉框
JTextArea jta;// 文字区域
Timer t;// 声明Timer对象
ArrayList<Integer> arhour = new ArrayList<Integer>();// 小时的队列
ArrayList<Integer> arminute = new ArrayList<Integer>();// 分钟的队列
/**
* 构造方法
*
* @param jcbhour
* @param jcbmin
* @param jta
*/
public ClockListener(JComboBox jcbhour, JComboBox jcbmin, JTextArea jta) {
this.jcbhour = jcbhour;
this.jcbmin = jcbmin;
this.jta = jta;
t = new Timer();
}
/**
* 重写actionPerformed方法
*/
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("文件选择")) {
JFileChooser jc = new JFileChooser("src/");// 实例化JFileChooser对象
jc.setFileSelectionMode(JFileChooser.FILES_ONLY);// 设置只可以选择文件
FileNameExtensionFilter jnef = new FileNameExtensionFilter("WAV",
"wav");// 实例化后缀名对象
jc.setFileFilter(jnef);// 设置只可以选择这个后缀名
int returnVal = jc.showOpenDialog(jc);// 获取选择后的信息
if (returnVal == JFileChooser.APPROVE_OPTION) {// 如果操作可执行
path = jc.getSelectedFile().getAbsolutePath();// 获取当前文件的路径
}
}
if (e.getActionCommand().equals("设置")) {
if (path != null) {// 如果路径不为空
int hour = Integer.parseInt(jcbhour.getSelectedItem()
.toString());// 获取当前选择的小时
int minute = Integer.parseInt(jcbmin.getSelectedItem()
.toString());// 获取当前选择的分钟
boolean bol = true;// 设置标识符
// 如果以前出现过这个时间
for (int i = 0; i < arhour.size(); i++) {
if (arhour.get(i) == hour && arminute.get(i) == minute) {
bol = false;// 设置标识符为否
}
}
if (bol) {// 如果以前没出现过,添加小时和分钟到队列中
arhour.add(hour);
arminute.add(minute);
jta.append("您设置了闹钟" + hour + "点" + minute + "分\n");// 在JTextArea中显示
ClockTimer ct = new ClockTimer(hour, minute, path, 1);// 实例化ClockTimer类
t.schedule(ct, 2000, 3000);// 运行线程
} else {
JOptionPane.showMessageDialog(null, "已设置过该闹钟");// 否则弹出已设置该闹钟
}
} else {
JOptionPane.showMessageDialog(null, "请选择声音文件");// 弹出未选择声音文件
}
}
if (e.getActionCommand().equals("保存")) {
File file = new File("src/cn/tth/study0917/save.ct");// 创建file对象
if (!file.exists()) {// 如果file不存在
try {
file.createNewFile();// 创建file文件
} catch (IOException e1) {
e1.printStackTrace();
}
}
try {
FileOutputStream os = new FileOutputStream(file);// 创建文件输出流
DataOutputStream dos = new DataOutputStream(os);// 创建数据输出流
dos.writeInt(arhour.size());// 写入闹钟的个数
// 循环写入小时和分钟
for (int i = 0; i < arhour.size(); i++) {
dos.writeInt(arhour.get(i));
dos.writeInt(arminute.get(i));
}
dos.flush();// 强制写入
dos.close();// 关闭数据流
os.close();// 关闭文件流
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (e.getActionCommand().equals("读取")) {
File file = new File("src/cn/tth/study0917/save.ct");// 创建file文件
if (file.exists()) {// 如果文件存在
try {
arhour.clear();// 清除当前队列
arminute.clear();
FileInputStream fis = new FileInputStream(file);// 创建文件输入流
DataInputStream dis = new DataInputStream(fis);// 创建数据输入流
int size = dis.readInt();// 获取队列的个数
for (int i = 0; i < size; i++) {
int hour = dis.readInt();// 读取小时
int minute = dis.readInt();// 读取分钟
arhour.add(hour);
arminute.add(minute);
jta.append("您设置了闹钟" + hour + "点" + minute + "分\n");// 在JTextArea中显示
}
dis.close();// 关闭数据流
fis.close();// 关闭文件流
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
// 关于如何存入路径,目前还没有具体的解决方案,所以先设置一个固定路径
path = "G:\\JAVA\\Junior\\src\\fire.wav";
for (int i = 0; i < arhour.size(); i++) {
ClockTimer ct = new ClockTimer(arhour.get(i),
arminute.get(i), path, 1);// 根据读出的打开线程
t.schedule(ct, 2000, 3000);// 运行线程
}
} else {
JOptionPane.showMessageDialog(null, "找不到文件");// 文件不存在
}
}
if (e.getActionCommand().equals("清空")) {
arhour.clear();// 清除队列内容
arminute.clear();
// 这里没有关闭已经创建的Timer类
jta.setText("");// 设置JTextArea内容为空
JOptionPane.showMessageDialog(null, "已全部清空");// 显示已全部清空
}
if (e.getActionCommand().equals("关闭")) {
System.exit(0);// 关闭窗体
}
}
}
最后我们写线程的类:
public class ClockTimer extends TimerTask {
JTextField jtf;
int i;
int hour;
int minute;
String path;
AudioClip audio;
/**
* 构造方法
*
* @param jtf
* @param i
*/
public ClockTimer(JTextField jtf, int i) {
this.jtf = jtf;
this.i = i;
}
/**
* 构造方法
*
* @param hour
* @param minute
* @param path
* @param i
*/
@SuppressWarnings("deprecation")
public ClockTimer(int hour, int minute, String path, int i) {
this.hour = hour;
this.minute = minute;
this.path = path;
this.i = i;
try {
audio = Applet.newAudioClip((new File(path)).toURL());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
/**
* 重写run方法
*/
public void run() {
Calendar date = Calendar.getInstance();// 获取当前时间
int hour = date.get(Calendar.HOUR_OF_DAY);// 小时
int minute = date.get(Calendar.MINUTE);// 分钟
if (i == 0) {//如果是上面的时间
int year = date.get(Calendar.YEAR);// 年
int month = date.get(Calendar.MONTH);// 月
int day = date.get(Calendar.DAY_OF_MONTH);// 日
int second = date.get(Calendar.SECOND);// 秒
jtf.setText(year + "年" + month + "月" + day + "日" + hour + "时"
+ minute + "分" + second + "秒");// 设置JTextArea
}
if (i == 1) {//如果是闹钟
// 如果到了设定的时间
if (hour == this.hour && minute == this.minute) {
audio.play();// 播放声音
}
}
}
}