2013年10月8日 星期二

[Java]Alarm Clock with Multi-Thread //多執行緒實做鬧鐘


我試著用多執行緒來實作鬧鐘,如下:
I try to build an alarm clock with multi-thread, as below:

Interface

1. Time column: Show the time now.
2. Countdown column: For input the time of countdown number.
3. Button: For start/stop countdown or stop alarm.




Operating
1.      Set the time you want to countdown.
Ex:1 Hour

2.      Click “Set”, then G Click will start countdown.
2-1.If you want to pause or stop countdown, click “Stop”.

3.      When the time up, G Clock will show the “Time Up” and the ring.
4.      Click “Time Up”, the ring will stop.

Codes

為了便於維護,我習慣把程式檔分為 UI排版 跟 運算端
I'm used to separate the function code files to UI layout and function part, for easily maintain.

UI排版/UI layout
import java.awt.*;

public class GAlarmClock implements Runnable{
 
 Thread t;
 JLabel JLabel_temp= new JLabel();

 private JFrame frmGalarmclock;
 private JTextField hour_txt;
 private JTextField minute_txt;
 private JTextField second_txt;
 private JButton btnSet;
 
 boolean time_set=false;  //按鈕狀態, 未設定時間=false, 已設定時間=true
 MouseAdapter btnEvent;
 
 GAlarmClock_function gfunc= new GAlarmClock_function();



 /**
  * Launch the application.
  */
 public static void main(String[] args) {
  EventQueue.invokeLater(new Runnable() {
   public void run() {
    try {
     GAlarmClock window = new GAlarmClock();
     window.frmGalarmclock.setVisible(true);
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  });
 }

 /**
  * Create the application.
  */
 public GAlarmClock() {
  super();
  if(t==null){
   t = new Thread(this);
   t.start();
  }
  initialize();
  gfunc.functionLink(time_set, hour_txt, minute_txt, second_txt, btnSet);
  
 }

 /**
  * Initialize the contents of the frame.
  */
 private void initialize() {
  
  frmGalarmclock = new JFrame();
  frmGalarmclock.setTitle("G Clock_1.0");
  frmGalarmclock.setResizable(false);
  frmGalarmclock.setBounds(100, 100, 192, 294);
  frmGalarmclock.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frmGalarmclock.getContentPane().setLayout(null);
  
  JLabel lblNow = new JLabel("Now:");
  lblNow.setFont(new Font("新細明體", Font.PLAIN, 18));
  lblNow.setBounds(10, 10, 46, 23);
  frmGalarmclock.getContentPane().add(lblNow);
  
  JLabel currentTime_txt = new JLabel("");
  currentTime_txt.setFont(new Font("新細明體", Font.PLAIN, 32));
  currentTime_txt.setBounds(20, 43, 123, 40);
  frmGalarmclock.getContentPane().add(currentTime_txt);
  JLabel_temp = currentTime_txt;
  
  JLabel lblAlarm = new JLabel("Alarm:");
  lblAlarm.setFont(new Font("新細明體", Font.PLAIN, 18));
  lblAlarm.setBounds(10, 124, 58, 23);
  frmGalarmclock.getContentPane().add(lblAlarm);
  
  hour_txt = new JTextField();
  hour_txt.setHorizontalAlignment(SwingConstants.RIGHT);
  hour_txt.setText("0");
  hour_txt.setBounds(20, 160, 30, 30);
  frmGalarmclock.getContentPane().add(hour_txt);
  hour_txt.setColumns(10);
  
  JLabel label = new JLabel(":");
  label.setFont(new Font("新細明體", Font.PLAIN, 18));
  label.setBounds(60, 161, 8, 23);
  frmGalarmclock.getContentPane().add(label);
  
  minute_txt = new JTextField();
  minute_txt.setHorizontalAlignment(SwingConstants.RIGHT);
  minute_txt.setText("0");
  minute_txt.setColumns(10);
  minute_txt.setBounds(78, 160, 30, 30);
  frmGalarmclock.getContentPane().add(minute_txt);
  
  JLabel label_1 = new JLabel(":");
  label_1.setFont(new Font("新細明體", Font.PLAIN, 18));
  label_1.setBounds(118, 161, 8, 23);
  frmGalarmclock.getContentPane().add(label_1);
  
  second_txt = new JTextField();
  second_txt.setHorizontalAlignment(SwingConstants.RIGHT);
  second_txt.setText("0");
  second_txt.setColumns(10);
  second_txt.setBounds(136, 160, 30, 30);
  frmGalarmclock.getContentPane().add(second_txt);
  
  btnSet = new JButton("Set");
 
  btnSet.addMouseListener( btnEvent=new MouseAdapter() {
   @Override
   public void mouseClicked(MouseEvent arg0) {
    time_set = gfunc.countdown(hour_txt, minute_txt, second_txt, time_set);
    gfunc.buttonStatus(btnSet, time_set);
    }    
   });
  btnSet.setBounds(47, 212, 87, 23);
  frmGalarmclock.getContentPane().add(btnSet);
  
 }
 
 @Override
 public void run() {
  // TODO Auto-generated method stub
  while(true){
   gfunc.showClock(JLabel_temp, gfunc.clock());
   //second_txt.setText("100");
   try {Thread.sleep(1000);}catch (InterruptedException e) { }
  }
 }
 
}



運算端/Function part
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;

import javax.swing.*;
import javax.sound.sampled.*;

public class GAlarmClock_function{
 
 int time, time_tmp;
 boolean time_set;
 JTextField hours_tmp, minutes_tmp, seconds_tmp;
 JButton btnSet;

 
 public void functionLink(boolean time_set1, JTextField hours_tmp1, JTextField minutes_tmp1, JTextField seconds_tmp1, JButton btnSet1
){//連結本檔的物件 
  time_set = time_set1;
  hours_tmp = hours_tmp1; 
  minutes_tmp = minutes_tmp1;
  seconds_tmp = seconds_tmp1;
  btnSet = btnSet1;
 }
 
 
 public String clock(){//取得當下時間
  String now;
  now=new SimpleDateFormat("HH:mm:ss").format(Calendar.getInstance().getTime());  
  return now;  
 }
 
 public void showClock(JLabel a, String b){//顯示時間到JLabel a
  a.setText(b);
 }
 
 public int transformTime(String hours, String minutes,String seconds){
  int time;
  time = Integer.parseInt(hours)*3600 + Integer.parseInt(minutes)*60 + Integer.parseInt(seconds);
  return time;
 }
 

 public boolean countdown(JTextField hours, JTextField minutes, JTextField seconds, boolean a){ //倒數
  try{
   time_tmp = transformTime(hours.getText(), minutes.getText(), seconds.getText());
  }catch(NumberFormatException e){ //防止輸入非整數,全部輸入歸0
   hours.setText("0");
   minutes.setText("0");
   seconds.setText("0");
   //System.out.println(a);
   return a=false;
  }
  hours_tmp=hours;
  minutes_tmp=minutes;
  seconds_tmp=seconds;
  

  Thread t = new Thread(new Runnable(){
   public void run(){
    while(time_tmp!=0 && time_set==true){ //迴圈直到 倒數結束 or 按下按鈕改變狀態
     time_tmp--;  //開始倒數
     transformCount(time_tmp, hours_tmp, minutes_tmp, seconds_tmp);
     ////System.out.println(time_tmp);
     try {Thread.sleep(1000);}catch (InterruptedException e) { }
     }
    if(time_tmp==0) {timeUp();btnSet.setText("Time Up");}//時間到, 啟動鈴聲並讓按鈕顯示"Time Up"
    }  
   });
  
  if(a){
   time_set=false;
   t.interrupt();   
  }
  else{
   time_set=true;
   t.start();
   ////System.out.println(a);
  }
  
  return time_set;
 }
 
 public void transformCount(int time, JTextField hours, JTextField minutes, JTextField seconds){ //將總數轉回 時 分 秒
   hours.setText(Integer.toString(time/3600));
   minutes.setText(Integer.toString(((time%3600))/60));
   seconds.setText(Integer.toString(time%60));   
 }
 
 public void buttonStatus(JButton a, boolean b){
  if(b){a.setText("Stop");}
  else{a.setText("Set");}  
 }
 
 public void timeUp(){//時間到時的處理事件(前提為time_tmp=0)
  Thread t = new Thread(new Runnable(){
   public void run(){
    while(time_set){
     try {
      //System.out.println(time_set);

     // 建立 File 物件
     File sf = new File("0038.WAV");//此寫法時做是可行的,但用IDE測試時會找不到檔案,需指定絕對路徑(如下)
     //File sf = new File("E:\\workspace\\Java\\GAlarmClock\\src\\0038.WAV");
     // 取得聲音輸入串流
     AudioInputStream astr = AudioSystem.getAudioInputStream(sf);
     // 取得聲音形式
     AudioFormat afmt = astr.getFormat();
     // 建立訊號線資訊物件
     DataLine.Info inf = new DataLine.Info(SourceDataLine.class,afmt);
     // 取得符合指定訊號線資訊的訊號線
     SourceDataLine l = (SourceDataLine) AudioSystem.getLine(inf);
     // 以指定形式開啟訊號線
     l.open(afmt);
     // 開始訊號線的讀寫
     l.start();
     // 讀寫緩衝區
     byte[] buf = new byte[65536];
     // 從聲音串流讀入資料寫入混音器
     for( int n=0; (n=astr.read(buf,0,buf.length))>0; )
     {l.write(buf,0,n);}
     // 清掉混音器內的資料
     l.drain();
     // 關閉
     l.close();
     } catch (Exception e) { e.printStackTrace();}
     }   
    }  
   });
  t.start();
 }

 
}



Goal of Update

1.      Add dynamic effects on time up alarm, ex: color twinkling, window shake, etc…
2.      Add function that user can select the alarm ring file by self.
3.      Add function that the G Click window could be shrink to minimum size at the tool bar.
4.      Add effect that G Click window will show on the top will time up.

Program Link
https://docs.google.com/file/d/0B2SpFawN0Ts6RTA0RE53OFdjc1k/edit?usp=sharing

=======================

如果你有好的想法或發現漏洞,歡迎提供建議
If you have good idea or find any bug, welcome to advice me.
一起成長吧!
That's grow up together!

沒有留言:

張貼留言