任务倒计时App

设计背景

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

设计步骤

1. 写java源码

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

java 复制代码
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() {
            @Override
            public 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() {
                @Override
                public 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() {
            @Override
            public 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 layout
                    String paddedTimeText = timeText.replaceAll("\\b(\\d)\\b", "0$1");

                    // Format the time text with HTML tags to set different font sizes
                    String 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() {
            @Override
            public 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文件地址

  1. 用记事本写一个文件,内容为: java -jar "jar文件的地址" ,随后将文件后缀改为.bat

  2. win+R打开运行窗口,输入shell:startup,打开开机自启动文件夹,将前面得到的.bat文件放入这个文件夹中即可

相关推荐
EasyGBS1 分钟前
从接入到稳定播放:无插件直播H5视频流媒体播放器EasyPlayer.js如何撑起Web端流媒体
开发语言·前端·javascript
FfHUCisI4 分钟前
GMP 调度器:Go 并发的心脏是如何跳动的
开发语言·golang·php
Zzzzmo_6 分钟前
Spring MVC
java·spring·mvc·cookie/session
cfm_29149 分钟前
Spring核心设计模式
java·spring·设计模式
Java小白笔记10 分钟前
Java 实现阿里云 OSS 文件上传链路:普通上传、秒传、分片与断点续传
java·开发语言·数据库·spring·阿里云
传奇开心果编程12 分钟前
【Rust入门知识点学与练】第9课:Vec 动态数组
开发语言·学习·rust
卢锡荣16 分钟前
单芯掌控多口互联|乐得瑞 LDR6020 PD3.1 多通道 Type‑C 控制 SOC 芯片
c语言·开发语言
2333!!!!!16 分钟前
rocket新手一些常见问题
java·开发语言
yume_sibai17 分钟前
02-Rust 所有权与借用深入解析(底层原理 + 借用检查器 + 生命周期 + 内部可变性)
开发语言·后端·rust
xxwxx__20 分钟前
深入理解 C++ STL:stack、queue 与 deque 从使用到底层实现全解析
开发语言·c++·算法