任务倒计时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文件放入这个文件夹中即可

相关推荐
游戏开发爱好者82 分钟前
H5 混合应用加密 Web 资源暴露到 IPA 层防护的完整技术方案
android·前端·ios·小程序·uni-app·iphone·webview
墨雪不会编程5 分钟前
C++基础语法篇八 ——【类型转换、再探构造、友元】
java·开发语言·c++
老毛肚10 分钟前
登录架构设计
java·开发语言
月明长歌10 分钟前
【码道初阶】【牛客BM30】二叉搜索树与双向链表:java中以引用代指针操作的艺术与陷阱
java·数据结构·算法·leetcode·二叉树·笔试·字节跳动
南棱笑笑生11 分钟前
20251215给飞凌OK3588-C开发板适配Rockchip原厂的Buildroot【linux-6.1】系统时统计eth1的插拔次数
linux·c语言·开发语言·rockchip
小坏讲微服务13 分钟前
Spring Boot4.0整合RabbitMQ死信队列详解
java·spring boot·后端·rabbitmq·java-rabbitmq
yuuki23323315 分钟前
【C++】内存管理
java·c++·算法
消失的旧时光-194319 分钟前
Java 线程池(第四篇):ScheduledThreadPoolExecutor 原理与定时任务执行机制全解析
java·开发语言
刃神太酷啦19 分钟前
Linux 进程核心原理精讲:从体系结构到实战操作(含 fork / 状态 / 优先级)----《Hello Linux!》(6)
java·linux·运维·c语言·c++·算法·leetcode
利刃大大21 分钟前
【JavaSE】十五、线程同步wait | notify && 单例模式 && 阻塞队列 && 线程池 && 定时器
java·单例模式·线程池·定时器·阻塞队列