定时闹钟预览版EXE下载链接:https://files.cnblogs.com/files/rekent/ReadytoRelax_jar.zip
功能说明:
实现了一个休息提醒器,用户首先设定一个倒计时时间(HH:MM:SS),每走完这个时间便会弹出提醒,让用户停止工作,起身休息。
休息回来工作时只需点击弹窗上的继续工作便可以继续以当前时间继续开始倒计时。
涉及技术:
使用类似Timer的定时器来推迟提醒线程的执行便可完成程序的主体部分,再辅以JavaFX、AWT来构建GUI界面即可。
此处使用ScheduledThreadPoolExecutor(点击此处获取该线程池的具体用法)这个线程池来实现延时执行的功能。
当前涉及的问题:
点击开始计时后,无法停止计时(无法获取到线程池中的线程并终止它);
线程池的进程不会因为JavaFX程序的关闭而结束,两者这件没有相互约束的关系;
源代码(一):(点击事件)
@FXML private TextField AlarmSecond; @FXML private TextField AlarmMiunte; @FXML private TextField AlarmHour; @FXML private javafx.scene.control.Button begin; @FXML public void beginCountDown(ActionEvent event) throws AWTException, InterruptedException { ScheduledThreadPoolExecutor threadPool=new ScheduledThreadPoolExecutor(10); //01.对TextField中数字的判断 List<Integer> valueList=new ArrayList<>(); String second=AlarmSecond.getText(); String miunte=AlarmMiunte.getText(); String hour=AlarmHour.getText(); if(second==null){ second="0"; } if(miunte==null){ miunte="0"; } if(hour==null){ hour="0"; } if(!((second.matches("[0-9]*"))&&(miunte.matches("[0-9]*"))&&(hour.matches("[0-9]*")))){ Alert alert=new Alert(Alert.AlertType.ERROR); alert.showAndWait(); return; } int int_second=Integer.parseInt(second); int int_miunte=Integer.parseInt(miunte); int int_hour=Integer.parseInt(hour); if(int_hour+int_miunte+int_second<=0){ Alert alert=new Alert(Alert.AlertType.ERROR); alert.showAndWait(); return; } valueList.add(int_second); valueList.add(int_miunte); valueList.add(int_hour); //02.计算Long时间类型,单位为MILLISECONDS long workingTime=new SpinnerUtil().Time2Millseconds(valueList.get(2),valueList.get(1),valueList.get(0)); String button_show=begin.getText(); if(button_show.equals("开始计时")){ begin.setText("停止计时"); System.out.println("倒计时时长:"+ valueList.get(2) +"H "+valueList.get(1)+"M "+valueList.get(0)+"S"); //03.创建一个对话框提醒线程 Runnable CountingAndShow=new Runnable() { @Override public void run() { begin.setText("开始计时"); System.out.println("Counting Over,Have a rest!"); Object[] options = {"继续工作","下班啦"}; int response= JOptionPane.showOptionDialog(new JFrame(), "休息一下吧~","",JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); if(response==0){ try { beginCountDown(event); } catch (AWTException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } }; //04.创建一个JavaFX Task任务,并将线程加入线程池中 Task countingTimer=new Task() { @Override protected Object call() throws Exception { threadPool.schedule(CountingAndShow,workingTime,TimeUnit.MILLISECONDS); return null; } }; countingTimer.run(); } else { //此处代码并没有效果 System.out.println("Stop Current Counting"); threadPool.shutdownNow(); begin.setText("开始计时"); } }
源代码(二)以及BUG修复理念
采用Timer来实现停止功能,在Controller中建立一个私有的Timer对象,这样使每次点击都能是同一个Timer对象。
停止计时--->调用Timer的Cancel()函数,即可关闭整个Timer(也会结束这个Timer线程),此时再重新实例化一个Timer即可。
private Timer timer; //新需要保证暂停和开始调用的为同一个Timer对象,所以在前面调用一个私有的对象,在后面在对其实例化 public Controller() { timer=new Timer(); } @FXML public void beginCountDown(ActionEvent event) throws AWTException, InterruptedException { //01.对TextField中数字的判断 String second=AlarmSecond.getText(); String miunte=AlarmMiunte.getText(); String hour=AlarmHour.getText(); //02.添加对为空时的自主处理方式 if(second==null){ second="0"; } if(miunte==null){ miunte="0"; } if(hour==null){ hour="0"; } //03.添加对输入模式的限制 if(!((second.matches("[0-9]*"))&&(miunte.matches("[0-9]*"))&&(hour.matches("[0-9]*")))){ Alert alert=new Alert(Alert.AlertType.ERROR); alert.showAndWait(); return; } int int_second=Integer.parseInt(second); int int_miunte=Integer.parseInt(miunte); int int_hour=Integer.parseInt(hour); if(int_hour<0||int_miunte<0||int_second<0||(int_hour+int_miunte+int_second<=0)){ Alert alert=new Alert(Alert.AlertType.ERROR); alert.showAndWait(); return; } //02.计算Long时间类型,单位为MILLISECONDS long workingTime=new SpinnerUtil().Time2Millseconds(int_hour,int_miunte,int_second); String button_show=begin.getText(); if(button_show.equals("开始计时")){ begin.setText("停止计时"); System.out.println("倒计时时长:"+ int_hour +"H "+int_miunte+"M "+int_second+"S"); //03.创建一个对话框提醒线程 TimerTask timerTask=new TimerTask() { @Override public void run() { System.out.println("run timeTask"); Platform.runLater(() -> { begin.setText("开始计时"); System.out.println("Counting Over,Have a rest!"); Object[] options = {"继续工作", "下班啦"}; int response = JOptionPane.showOptionDialog(new JFrame(), "休息一下吧~", "", JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); if (response == 0) { try { beginCountDown(event); } catch (AWTException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }); } }; //04.创建一个JavaFX Task任务,并将线程加入线程池中 Task countingTimer=new Task() { @Override protected Object call() throws Exception { timer.schedule(timerTask,workingTime); return null; } }; countingTimer.run(); System.out.println("run timer"); } else { System.out.println("Stop Current Counting"); timer.cancel(); begin.setText("开始计时"); timer=new Timer(); } }