Java 实现一个带提醒的定时器

定时闹钟预览版EXE下载链接:https://files.cnblogs.com/files/rekent/ReadytoRelax_jar.zip


功能说明:

  实现了一个休息提醒器,用户首先设定一个倒计时时间(HH:MM:SS),每走完这个时间便会弹出提醒,让用户停止工作,起身休息。

  休息回来工作时只需点击弹窗上的继续工作便可以继续以当前时间继续开始倒计时。


涉及技术:

  使用类似Timer的定时器来推迟提醒线程的执行便可完成程序的主体部分,再辅以JavaFXAWT来构建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();
        }
    }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏zhisheng

渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(上)

上篇文章写了 ElasticSearch 源码解析 —— 环境搭建 ,其中里面说了启动 打开 server 模块下的 Elasticsearch 类:org.e...

1381
来自专栏Android知识点总结

1-SII--SharedPreferences完美封装

1354
来自专栏编码小白

tomcat请求处理分析(六)servlet的处理过程

1.1.1.1  servlet的解析过程 servlet的解析分为两步实现,第一个是匹配到对应的Wrapper,第二个是加载对应的servlet并进行数据,这...

7217
来自专栏刘望舒

LeakCanary看这一篇文章就够了

LeakCanary是Square公司基于MAT开源的一个内存泄漏检测工具,在发生内存泄漏的时候LeakCanary会自动显示泄漏信息。

2.4K5
来自专栏程序猿DD

Spring框架中的设计模式(四)​

本文是Spring框架中使用的设计模式第四篇。本文将在此呈现出新的3种模式。一开始,我们会讨论2种结构模式:适配器和装饰器。在第三部分和最后一部分,我们将讨论单...

3966
来自专栏Pythonista

Django之ORM数据库

            django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 , 引擎名称:django.db.backends.sqli...

1411
来自专栏跟着阿笨一起玩NET

以读取博客园随笔备份为例 将xml 序列化成json,再序列化成对象

资源下载:http://files.cnblogs.com/codealone/ConsoleApplication2.zip

1031
来自专栏分布式系统进阶

Librdkafka的操作处理队列

2882
来自专栏瓜大三哥

Yaffs_guts(三)

1.垃圾回收 1.static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks)//块初始化 ...

2255
来自专栏何俊林

LeakCanary的原理,你知道么?

3042

扫码关注云+社区

领取腾讯云代金券