当前位置: 首页 > news >正文

任务倒计时App

设计背景

在某一阶段可能需要给自己设置长期任务,比如找工作、考研等,需要一个单纯的任务计时工具,设置完任务的目标时间后,每次打开App时都能直接看到最新的剩余时间

设计步骤

1. 写java源码

由于需要界面显示,需要用到swing库等,以下是源码

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.List;public class CountdownTimer extends JFrame {private JTextField taskNameField;private JTextField dateTimeField;private JLabel messageLabel;private static final String FILE_PATH = "tasks.txt";private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");private List<Task> tasks = new ArrayList<>();private JPanel tasksPanel;public CountdownTimer() {setTitle("倒计时器");setSize(600, 400);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setLocationRelativeTo(null);// 创建输入框和按钮taskNameField = new JTextField(10);dateTimeField = new JTextField(20);messageLabel = new JLabel("输入任务名和目标时间 (yyyy-MM-dd HH:mm:ss)", SwingConstants.CENTER);JButton addButton = new JButton("添加任务");// 添加事件监听器addButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {addTask();}});// 布局setLayout(new BorderLayout());JPanel inputPanel = new JPanel();inputPanel.add(new JLabel("任务名:"));inputPanel.add(taskNameField);inputPanel.add(new JLabel("目标时间:"));inputPanel.add(dateTimeField);inputPanel.add(addButton);tasksPanel = new JPanel();tasksPanel.setLayout(new BoxLayout(tasksPanel, BoxLayout.Y_AXIS));add(inputPanel, BorderLayout.NORTH);add(new JScrollPane(tasksPanel), BorderLayout.CENTER);add(messageLabel, BorderLayout.SOUTH);// 读取并启动倒计时loadTasks();}private void addTask() {String taskName = taskNameField.getText();String targetDateTimeStr = dateTimeField.getText();try {LocalDateTime targetDateTime = LocalDateTime.parse(targetDateTimeStr, formatter);Task task = new Task(taskName, targetDateTime);tasks.add(task);saveTasks();displayTasks();taskNameField.setText("");dateTimeField.setText("");messageLabel.setText("任务添加成功!");} catch (Exception ex) {messageLabel.setText("请输入正确的日期时间格式: yyyy-MM-dd HH:mm:ss");}}private void displayTasks() {tasksPanel.removeAll();for (Task task : tasks) {JPanel taskPanel = new JPanel(new BorderLayout());JLabel taskLabel = new JLabel();taskPanel.add(taskLabel, BorderLayout.CENTER);JButton deleteButton = new JButton("删除");deleteButton.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {tasks.remove(task);saveTasks();displayTasks();}});taskPanel.add(deleteButton, BorderLayout.EAST);tasksPanel.add(taskPanel);startTimer(task, taskLabel);}tasksPanel.revalidate();tasksPanel.repaint();}private void startTimer(Task task, JLabel taskLabel) {java.util.Timer timer = new java.util.Timer();timer.scheduleAtFixedRate(new java.util.TimerTask() {@Overridepublic void run() {LocalDateTime now = LocalDateTime.now();long seconds = ChronoUnit.SECONDS.between(now, task.getTargetDateTime());if (seconds <= 0) {taskLabel.setText("<html>" + task.getName() + ": <font size='5'>时间到了!</font></html>");timer.cancel();} else {long years = ChronoUnit.YEARS.between(now, task.getTargetDateTime());now = now.plusYears(years);long months = ChronoUnit.MONTHS.between(now, task.getTargetDateTime());now = now.plusMonths(months);long days = ChronoUnit.DAYS.between(now, task.getTargetDateTime());now = now.plusDays(days);long hours = ChronoUnit.HOURS.between(now, task.getTargetDateTime());now = now.plusHours(hours);long minutes = ChronoUnit.MINUTES.between(now, task.getTargetDateTime());now = now.plusMinutes(minutes);long secs = ChronoUnit.SECONDS.between(now, task.getTargetDateTime());String timeText = String.format("%d年 %d月 %d天 %02d小时 %02d分 %02d秒",years, months, days, hours, minutes, secs);// Pad numbers with zeros to ensure stable layoutString paddedTimeText = timeText.replaceAll("\\b(\\d)\\b", "0$1");// Format the time text with HTML tags to set different font sizesString formattedText = "<html>" + task.getName() + ": ";formattedText += "<font size='5'>" + paddedTimeText + "</font></html>";taskLabel.setText(formattedText);}}}, 0, 1000);}private void saveTasks() {try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_PATH))) {for (Task task : tasks) {writer.write(task.getName() + ";" + task.getTargetDateTime().format(formatter));writer.newLine();}} catch (IOException e) {e.printStackTrace();}}private void loadTasks() {tasks.clear();try (BufferedReader reader = new BufferedReader(new FileReader(FILE_PATH))) {String line;while ((line = reader.readLine()) != null) {String[] parts = line.split(";");if (parts.length == 2) {String taskName = parts[0];LocalDateTime targetDateTime = LocalDateTime.parse(parts[1], formatter);tasks.add(new Task(taskName, targetDateTime));}}displayTasks();} catch (IOException e) {messageLabel.setText("尚未设置任务。");}}public static void main(String[] args) {SwingUtilities.invokeLater(new Runnable() {@Overridepublic void run() {new CountdownTimer().setVisible(true);}});}
}class Task {private String name;private LocalDateTime targetDateTime;public Task(String name, LocalDateTime targetDateTime) {this.name = name;this.targetDateTime = targetDateTime;}public String getName() {return name;}public LocalDateTime getTargetDateTime() {return targetDateTime;}
}

2. 将java源码转为jar文件

  JAR文件是一种软件包文件格式,通常用于聚合大量的Java类文件、相关的元数据和资源(文本、图片等)文件到一个文件,以便开发Java平台应用软件或库。
  将源码转为jar文件具体可参考这篇博客:如何将.java文件转为.jar

3. 使用launch4j工具将jar文件转为exe可执行文件

具体步骤可参考这篇博客:luanch4j转exe

App展示

这是App的界面演示
在这里插入图片描述
App自取链接:https://pan.baidu.com/s/1C5Nc5ZsdFsSVU3-SEEsdVA
提取码:dddd

开机自启动

若是想开机直接能看到程序启动,
1.记好转好的jar文件地址
2. 用记事本写一个文件,内容为: java -jar “jar文件的地址” ,随后将文件后缀改为.bat
3. win+R打开运行窗口,输入shell:startup,打开开机自启动文件夹,将前面得到的.bat文件放入这个文件夹中即可

相关文章:

  • 公司面试题总结(二)
  • BC C language
  • 【运维】Ubuntu换硬盘扩容
  • web刷题记录(5)
  • Python网络爬虫4-实战爬取pdf
  • PDF编辑与修正 提高工作效率 Enfocus PitStop Pro 2022 中文
  • Spring应用如何打印access日志和out日志(用于分析请求总共在服务耗费多长时间)
  • Mybatis06-动态SQL
  • K8s 卷快照类
  • WindTerm使用SSH密钥连接阿里云实例,服务器设置SSH密钥登录
  • NIFI启动后密码在哪里
  • STM32MP135裸机编程:配置RCC,修改主频到1GHz
  • XX食品有限公司智能制造汇报材料(71页PPT)
  • Claude3 注册及升级教程(包含封号解决方法)
  • VBA即用型代码手册:删除空列Delete Empty Columns
  • 【附node操作实例】redis简明入门系列—字符串类型
  • CSS相对定位
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • spark本地环境的搭建到运行第一个spark程序
  • sublime配置文件
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • webpack4 一点通
  • 猴子数据域名防封接口降低小说被封的风险
  • 跨域
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 优化 Vue 项目编译文件大小
  • puppet连载22:define用法
  • zabbix3.2监控linux磁盘IO
  • ​queue --- 一个同步的队列类​
  • ![CDATA[ ]] 是什么东东
  • # AI产品经理的自我修养:既懂用户,更懂技术!
  • # linux从入门到精通(三)
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (ISPRS,2021)具有遥感知识图谱的鲁棒深度对齐网络用于零样本和广义零样本遥感图像场景分类
  • (二)Linux——Linux常用指令
  • (篇九)MySQL常用内置函数
  • (一)面试需要掌握的技巧
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • ***监测系统的构建(chkrootkit )
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .Net Core 微服务之Consul(二)-集群搭建
  • .NET 简介:跨平台、开源、高性能的开发平台
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .Net+SQL Server企业应用性能优化笔记4——精确查找瓶颈
  • .NET8 动态添加定时任务(CRON Expression, Whatever)
  • .net的socket示例
  • .Net下的签名与混淆
  • @requestBody写与不写的情况
  • [ vulhub漏洞复现篇 ] JBOSS AS 5.x/6.x反序列化远程代码执行漏洞CVE-2017-12149
  • [ 常用工具篇 ] AntSword 蚁剑安装及使用详解
  • []指针
  • [bbk5179]第66集 第7章 - 数据库的维护 03
  • [CakePHP] 在Controller中使用Helper
  • [Day 36] 區塊鏈與人工智能的聯動應用:理論、技術與實踐