设计背景
在某一阶段可能需要给自己设置长期任务,比如找工作、考研等,需要一个单纯的任务计时工具,设置完任务的目标时间后,每次打开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文件放入这个文件夹中即可