吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2243|回复: 29
收起左侧

[Python 转载] 借用AI开发了一套多任务倒计时工具 - 支持系统托盘和悬浮窗,让时间管理更容易!

  [复制链接]
fboy19871218 发表于 2026-3-5 11:30
本帖最后由 fboy19871218 于 2026-3-9 10:25 编辑

多任务倒计时工具 - 支持系统托盘和悬浮窗,让时间管理更容易(已更新版本与源码,在19楼)

## 软件介绍
这是一款功能强大、界面美观的多任务倒计时工具,支持同时管理多个倒计时任务和定时提醒,特别适合需要时间管理的用户。软件采用现代化的界面设计,操作简单直观,是日常工作和生活的得力助手。

## 功能特点
### 核心功能
- 多任务管理 :同时支持多个倒计时任务和定时提醒,最多可添加10个任务
- 系统托盘 :最小化到系统托盘,不占用桌面空间
- 悬浮窗 :右下角显示任务列表和目标时间,随时查看任务状态
- 任务存档 :退出后自动保存任务,下次启动时恢复
- 智能提醒 :任务到期时弹出提醒窗口,不同类型任务显示不同颜色
- 目标时间显示 :实时显示每个任务的目标北京时间
### 特色功能
- 任务复制 :支持复制现有任务,快速创建类似任务
- 时间计算 :智能计算任务剩余时间,确保目标时间准确无误
- 界面优化 :响应式布局,美观的颜色区分,良好的用户体验
- 一键操作 :简单直观的操作界面,新手也能轻松上手
## 界面预览
### 主界面




### 悬浮窗


### 提醒窗口


## 如何使用
### 1. 添加倒计时任务
1. 在「倒计提醒」区域输入任务名称
2. 设置倒计时时长(时、分、秒)
3. 点击「添加任务」按钮
4. 任务将显示在「当前任务列表」中
### 2. 添加定时提醒
1. 在「定时提醒」区域输入提醒名称
2. 设置提醒日期和时间
3. 点击「添加提醒」按钮
4. 任务将显示在「当前任务列表」中
### 3. 管理任务
- 删除任务 :点击任务行中的「删除」按钮
- 复制任务 :点击任务行中的「复制」按钮,修改后创建新任务
### 4. 系统托盘操作
- 最小化 :点击窗口最小化按钮,程序将最小化到系统托盘
- 显示窗口 :点击托盘图标,选择「显示窗口」
- 显示悬浮窗 :点击托盘图标,选择「显示悬浮窗」
- 退出程序 :点击托盘图标,选择「退出」
### 5. 悬浮窗使用
- 查看任务 :悬浮窗显示所有当前运行的任务
- 目标时间 :每个任务下方显示目标北京时间
- 隐藏悬浮窗 :点击悬浮窗中的「隐藏」按钮
## 使用场景
### 工作场景
- 会议提醒 :设置会议开始前的倒计时
- 任务截止 :追踪项目截止时间
- 休息提醒 :定时提醒休息,保护眼睛
### 生活场景
- 烹饪计时 :设置烹饪时间提醒
- 运动计时 :追踪运动时长
- 约会提醒 :重要约会时间提醒
## 技术特性
- 开发语言 :Python 3.11
- GUI框架 :Tkinter
- 系统托盘 :pystray
- 图标支持 :Pillow
- 打包工具 :PyInstaller
- 压缩工具 :UPX
## 常见问题
### Q: 任务数量有限制吗?
A: 为了保证界面美观和性能,最多支持同时运行10个任务。

### Q: 任务会在电脑重启后保存吗?
A: 是的,程序会在退出时自动保存任务,下次启动时恢复。

### Q: 可以修改任务的目标时间吗?
A: 可以通过复制任务的方式修改目标时间,创建新任务。

### Q: 提醒窗口会一直显示吗?
A: 提醒窗口会在任务到期时弹出,需要手动点击「关闭」按钮关闭。

## 下载链接
### 程序下载
- 主程序 : time.exe
- 大小 :约15MB
- 版本 :v1.0.0
- 适用系统 :Windows 7/8/10/11
### 注意事项
1. 程序为绿色版,无需安装,双击即可运行
2. 首次运行时会在程序目录生成tasks.json文件,用于保存任务
3. 请确保程序所在目录有写入权限
## 更新日志
### v1.0.0
- 初始版本
- 支持多任务倒计时和定时提醒
- 系统托盘和悬浮窗功能
- 任务存档和恢复
- 目标时间显示
## 免责声明
本软件仅供个人学习和使用,请勿用于商业用途。如有侵权,请联系作者删除。


源码:
[Python] 纯文本查看 复制代码
import tkinter as tk
from tkinter import ttk, messagebox
import time
import threading
import pystray
from PIL import Image, ImageDraw
import os
import sys
import tempfile
import json

# 取消单例模式,允许多实例运行
def singleton():
    """允许多实例运行"""
    return True

# 自定义消息框函数,确保在屏幕居中显示
def show_center_messagebox(title, message, icon='warning'):
    """显示居中的消息框"""
    # 创建自定义消息框窗口
    msg_window = tk.Toplevel()
    msg_window.title(title)
    msg_window.resizable(False, False)
    msg_window.transient()  # 设置为临时窗口
    msg_window.grab_set()  # 模态窗口
    
    # 固定窗口大小,确保完整显示所有内容
    window_width = 400
    window_height = 180
    
    # 计算屏幕中心位置
    screen_width = msg_window.winfo_screenwidth()
    screen_height = msg_window.winfo_screenheight()
    x = (screen_width - window_width) // 2
    y = (screen_height - window_height) // 2
    msg_window.geometry(f"{window_width}x{window_height}+{x}+{y}")
    
    # 设置窗口样式
    msg_window.configure(bg="#ffffff")
    
    # 消息文本
    message_label = ttk.Label(msg_window, text=message, wraplength=window_width-40, justify=tk.CENTER, font= ("Microsoft YaHei", 11))
    message_label.pack(pady=(20, 20), padx=20, fill=tk.BOTH, expand=True)
    
    # 确定按钮
    def on_ok():
        msg_window.destroy()
    
    # 创建按钮
    ok_button = ttk.Button(msg_window, text="确定", command=on_ok, width=10)
    ok_button.pack(pady=(0, 20))
    
    # 等待窗口关闭
    msg_window.wait_window()

class CountdownApp:
    def __init__(self, root):
        self.root = root
        # 先隐藏窗口,避免启动时闪烁
        self.root.withdraw()
        
        self.root.title("多任务倒计时工具")
        # 设置窗口图标
        import os
        import sys
        # 获取当前脚本所在目录
        if getattr(sys, 'frozen', False):
            # 打包后的环境
            if hasattr(sys, '_MEIPASS'):
                # 使用 PyInstaller 的临时目录
                script_dir = sys._MEIPASS
            else:
                # 回退到可执行文件目录
                script_dir = os.path.dirname(sys.executable)
        else:
            # 开发环境
            script_dir = os.path.dirname(os.path.abspath(__file__))
        icon_path = os.path.join(script_dir, 'favicon.ico')
        try:
            if os.path.exists(icon_path):
                self.root.iconbitmap(icon_path)
        except:
            pass  # 如果图标文件不存在或设置失败,忽略错误
        # 基础窗口尺寸
        self.root.geometry("920x550")
        # 设置窗口居中
        self.center_window(920, 550)
        
        # 完成所有设置后显示窗口
        self.root.deiconify()
        
        # 固定窗口大小,不可调整
        self.root.resizable(False, False)
        self.root.configure(bg="#ffffff")

        # ===== 自定义样式 =====
        self.style = ttk.Style(self.root)
        # 设置主题(基础主题)
        self.style.theme_use("clam")
        # 自定义字体 - 统一白底黑字加粗
        self.style.configure(".", font=("Microsoft YaHei", 10, "bold"), foreground="#000000", background="#ffffff")
        # 按钮样式
        self.style.configure("TButton", 
                            font=("Microsoft YaHei", 10, "bold"),
                            background="#22c55e",
                            foreground="white",
                            padding=6)
        self.style.map("TButton",
                       background=[("active", "#16a34a")])
        # 复制按钮样式
        self.style.configure("Copy.TButton", 
                            font=("Microsoft YaHei", 10, "bold"),
                            background="#f59e0b",
                            foreground="white",
                            padding=6)
        self.style.map("Copy.TButton",
                       background=[("active", "#d97706")])
        # 标签样式
        self.style.configure("Title.TLabel", 
                             font=("Microsoft YaHei", 12, "bold"),
                             foreground="#000000",
                             background="#ffffff")
        self.style.configure("Task.TLabel", 
                             font=("Microsoft YaHei", 10, "bold"),
                             foreground="#000000",
                             background="#ffffff")
        self.style.configure("Warning.TLabel",
                             font=("Microsoft YaHei", 10, "bold"),
                             foreground="#dc2626",
                             background="#ffffff")
        # 倒计时任务样式(蓝色背景,加粗字体,蓝色边框)
        self.style.configure("Countdown.TFrame",
                             background="#e6f0ff",
                             bordercolor="#3b82f6",
                             relief="solid",
                             borderwidth=2)
        self.style.configure("Countdown.TLabel",
                             font=("Microsoft YaHei", 10, "bold"),
                             foreground="#000000",
                             background="#e6f0ff")
        # 定时提醒任务样式(绿色背景,加粗字体,绿色边框)
        self.style.configure("Reminder.TFrame",
                             background="#dcfce7",
                             bordercolor="#22c55e",
                             relief="solid",
                             borderwidth=2)
        self.style.configure("Reminder.TLabel",
                             font=("Microsoft YaHei", 10, "bold"),
                             foreground="#000000",
                             background="#dcfce7")
        # 列表框架样式
        self.style.configure("List.TFrame",
                             background="#ffffff")
        # 标签框架样式
        self.style.configure("Title.TFrame",
                             background="#ffffff",
                             bordercolor="#000000",
                             relief="ridge",
                             borderwidth=6)
        # 输入框样式
        self.style.configure("TEntry",
                             fieldbackground="#ffffff",
                             foreground="#000000",
                             bordercolor="#000000",
                             relief="ridge",
                             borderwidth=2)
        # 下拉框样式
        self.style.configure("TCombobox",
                             fieldbackground="#ffffff",
                             foreground="#000000",
                             bordercolor="#000000",
                             relief="ridge",
                             borderwidth=2)
        
        # 存储倒计时任务
        self.countdown_tasks = []
        # 存储提醒任务
        self.reminder_tasks = []
        # 存储当前显示的提醒窗口
        self.alert_windows = []
        # 托盘图标
        self.tray_icon = None
        # 绑定窗口最小化事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)
        # 绑定窗口最小化事件
        self.root.bind("<Unmap>", self.on_minimize)
        # 延迟初始化托盘图标
        self.root.after(100, self.init_tray_icon)
        # 启动任务更新循环
        self.root.after(100, self.update_tasks)

        # ===== 界面布局 =====
        # 1. 标题区域
        title_frame = ttk.Frame(root, style="Title.TFrame")
        title_frame.pack(fill=tk.X, padx=20, pady=0)
        title_label = ttk.Label(title_frame, text="多任务倒计时工具", style="Title.TLabel")
        title_label.pack(anchor=tk.CENTER, pady=20)

        # 2. 输入区域(带边框)
        input_frame = ttk.LabelFrame(root, text="倒计提醒", padding="10", style="Title.TFrame")
        input_frame.pack(fill=tk.X, padx=20, pady=0)

        # 输入网格布局
        ttk.Label(input_frame, text="任务名称:", style="Task.TLabel").grid(row=0, column=0, padx=5, pady=4, sticky=tk.E)
        self.name_entry = ttk.Entry(input_frame, width=15)
        self.name_entry.grid(row=0, column=1, padx=5, pady=4)
        self.name_entry.insert(0, "我的倒计提醒")  # 默认名称
        self.name_entry.config(font= ("Microsoft YaHei", 10))
        # 绑定点击事件,清除默认文本
        self.name_entry.bind("<FocusIn>", self.clear_default_text)

        # 时间输入组
        time_frame = ttk.Frame(input_frame)
        time_frame.grid(row=0, column=2, padx=10, pady=4, columnspan=1)
        ttk.Label(time_frame, text="时长:", style="Task.TLabel").grid(row=0, column=0, padx=5)
        self.hour_entry = ttk.Entry(time_frame, width=6)
        self.hour_entry.grid(row=0, column=1, padx=2)
        self.hour_entry.insert(0, "0")
        ttk.Label(time_frame, text="时", style="Task.TLabel").grid(row=0, column=2, padx=2)

        self.minute_entry = ttk.Entry(time_frame, width=6)
        self.minute_entry.grid(row=0, column=3, padx=2)
        self.minute_entry.insert(0, "0")
        ttk.Label(time_frame, text="分", style="Task.TLabel").grid(row=0, column=4, padx=2)

        self.second_entry = ttk.Entry(time_frame, width=6)
        self.second_entry.grid(row=0, column=5, padx=2)
        self.second_entry.insert(0, "10")
        ttk.Label(time_frame, text="秒                                           ", style="Task.TLabel").grid(row=0, column=6, padx=2)

        # 新增按钮(使用默认TButton样式,确保可见)
        add_btn = ttk.Button(input_frame, text="添加任务", command=self.add_countdown)
        add_btn.grid(row=0, column=3, padx=30, pady=4)

        # 3. 定时提醒区域
        reminder_frame = ttk.LabelFrame(root, text="定时提醒", padding="10", style="Title.TFrame")
        reminder_frame.pack(fill=tk.X, padx=20, pady=0)

        # 定时提醒输入 - 调整布局以适应1050宽度
        ttk.Label(reminder_frame, text="提醒名称:", style="Task.TLabel").grid(row=0, column=0, padx=5, pady=4, sticky=tk.E)
        self.reminder_name_entry = ttk.Entry(reminder_frame, width=15)
        self.reminder_name_entry.grid(row=0, column=1, padx=5, pady=4)
        self.reminder_name_entry.insert(0, "我的定时提醒")  # 默认名称
        self.reminder_name_entry.config(font= ("Microsoft YaHei", 10))
        # 绑定点击事件,清除默认文本
        self.reminder_name_entry.bind("<FocusIn>", self.clear_reminder_default_text)

        # 日期时间选择
        ttk.Label(reminder_frame, text="提醒时间:", style="Task.TLabel").grid(row=0, column=2, padx=5, pady=4, sticky=tk.E)
        
        # 获取当前北京时间,并加上30秒
        import datetime
        now = datetime.datetime.now()
        reminder_time = now + datetime.timedelta(seconds=30)
        
        # 日期时间选择合并为一行
        datetime_frame = ttk.Frame(reminder_frame)
        datetime_frame.grid(row=0, column=2, padx=5, pady=4, columnspan=1, sticky=tk.W)
        
        # 日期部分
        ttk.Label(datetime_frame, text="日期:", style="Task.TLabel").pack(side=tk.LEFT, padx=1)
        self.reminder_year = ttk.Combobox(datetime_frame, width=5, values=[str(reminder_time.year), str(reminder_time.year+1)])
        self.reminder_year.pack(side=tk.LEFT, padx=1)
        self.reminder_year.set(str(reminder_time.year))
        
        ttk.Label(datetime_frame, text="年", style="Task.TLabel").pack(side=tk.LEFT, padx=0)
        self.reminder_month = ttk.Combobox(datetime_frame, width=3, values=[f"{i:02d}" for i in range(1, 13)])
        self.reminder_month.pack(side=tk.LEFT, padx=1)
        self.reminder_month.set(f"{reminder_time.month:02d}")
        
        ttk.Label(datetime_frame, text="月", style="Task.TLabel").pack(side=tk.LEFT, padx=0)
        self.reminder_day = ttk.Combobox(datetime_frame, width=3, values=[f"{i:02d}" for i in range(1, 32)])
        self.reminder_day.pack(side=tk.LEFT, padx=1)
        self.reminder_day.set(f"{reminder_time.day:02d}")
        ttk.Label(datetime_frame, text="日", style="Task.TLabel").pack(side=tk.LEFT, padx=5)
        
        # 时间部分
        ttk.Label(datetime_frame, text="时间:", style="Task.TLabel").pack(side=tk.LEFT, padx=1)
        self.reminder_hour = ttk.Combobox(datetime_frame, width=3, values=[f"{i:02d}" for i in range(24)])
        self.reminder_hour.pack(side=tk.LEFT, padx=1)
        self.reminder_hour.set(f"{reminder_time.hour:02d}")
        ttk.Label(datetime_frame, text="时", style="Task.TLabel").pack(side=tk.LEFT, padx=0)
        
        self.reminder_minute = ttk.Combobox(datetime_frame, width=3, values=[f"{i:02d}" for i in range(60)])
        self.reminder_minute.pack(side=tk.LEFT, padx=1)
        self.reminder_minute.set(f"{reminder_time.minute:02d}")
        ttk.Label(datetime_frame, text="分", style="Task.TLabel").pack(side=tk.LEFT, padx=1)
        
        # 新增秒选择
        self.reminder_second = ttk.Combobox(datetime_frame, width=3, values=[f"{i:02d}" for i in range(60)])
        self.reminder_second.pack(side=tk.LEFT, padx=1)
        self.reminder_second.set(f"{reminder_time.second:02d}")
        ttk.Label(datetime_frame, text="秒", style="Task.TLabel").pack(side=tk.LEFT, padx=1)
        
        # 添加提醒按钮 - 与添加任务按钮对齐
        add_reminder_btn = ttk.Button(reminder_frame, text="添加提醒", command=self.add_reminder)
        add_reminder_btn.grid(row=0, column=3, padx=10, pady=4)

        # 4. 主内容区域(左右布局)
        main_content_frame = ttk.Frame(root, style="List.TFrame")
        main_content_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=(0, 10))  # 保持左右内边距
        
        # 固定主内容区域宽度为880px(920-20*2)
        main_content_frame.update_idletasks()
        main_content_frame.config(width=880)
        
        # 当前任务列表,占据整个主内容区域
        left_frame = ttk.LabelFrame(main_content_frame, text="当前任务列表", padding="15", style="Title.TFrame")
        left_frame.place(x=0, y=0, width=880, relheight=1)  # 宽度880,占据整个主内容区域
        

        


        # 任务容器(带滚动条)
        self.task_canvas = tk.Canvas(left_frame, bg="#ffffff", highlightthickness=0)
        scrollbar = ttk.Scrollbar(left_frame, orient=tk.VERTICAL, command=self.task_canvas.yview)
        self.scrollable_frame = ttk.Frame(self.task_canvas, style="List.TFrame")

        # 创建窗口并保存引用
        scrollable_window = self.task_canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        
        # 绑定scrollable_frame的配置事件
        def on_frame_configure(event):
            try:
                if not self.task_canvas.winfo_exists():
                    return
                self.task_canvas.configure(scrollregion=self.task_canvas.bbox("all"))
                # 检查是否需要显示滚动条
                if self.task_canvas.winfo_height() > 0:  # 确保canvas已经初始化
                    if self.task_canvas.bbox("all")[3] > self.task_canvas.winfo_height():
                        if not scrollbar.winfo_ismapped():
                            scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
                            # 调整scrollable_window的宽度
                            self.task_canvas.itemconfig(scrollable_window, width=self.task_canvas.winfo_width() - scrollbar.winfo_width())
                    else:
                        if scrollbar.winfo_ismapped():
                            scrollbar.pack_forget()
                            # 调整scrollable_window的宽度
                            self.task_canvas.itemconfig(scrollable_window, width=self.task_canvas.winfo_width())
            except Exception as e:
                print(f"配置框架失败: {e}")
        
        self.scrollable_frame.bind("<Configure>", on_frame_configure)
        
        # 绑定canvas的配置事件,让scrollable_frame宽度随canvas调整
        def on_canvas_configure(event):
            try:
                if not self.task_canvas.winfo_exists():
                    return
                # 确保scrollable_frame宽度与canvas一致,减去滚动条的宽度
                if scrollbar.winfo_ismapped():
                    scrollbar_width = scrollbar.winfo_width()
                    self.task_canvas.itemconfig(scrollable_window, width=event.width - scrollbar_width)
                else:
                    self.task_canvas.itemconfig(scrollable_window, width=event.width)
            except Exception as e:
                print(f"配置画布失败: {e}")
        
        self.task_canvas.bind("<Configure>", on_canvas_configure)
        
        self.task_canvas.configure(yscrollcommand=scrollbar.set)

        self.task_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        # 加载任务存档
        self.load_tasks()
        

        

        




    def center_window(self, width, height):
        """将窗口居中显示"""
        # 获取屏幕尺寸
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        # 计算居中坐标
        x = (screen_width - width) // 2
        y = (screen_height - height) // 2
        # 设置窗口位置
        self.root.geometry(f"{width}x{height}+{x}+{y}")

    def clear_default_text(self, event):
        """点击任务名称输入框时清除默认文本"""
        if self.name_entry.get() == "我的倒计提醒":
            self.name_entry.delete(0, tk.END)
    
    def clear_reminder_default_text(self, event):
        """点击提醒名称输入框时清除默认文本"""
        if self.reminder_name_entry.get() == "我的定时提醒":
            self.reminder_name_entry.delete(0, tk.END)

    def add_countdown(self):
        """新增倒计时任务"""
        # 检查任务数量限制
        total_tasks = len(self.countdown_tasks) + len(self.reminder_tasks)
        if total_tasks >= 10:
            show_center_messagebox("任务数量限制", "当前任务列表最多只能添加10条任务,请先删除部分任务后再添加!")
            return
            
        # 1. 输入验证
        name = self.name_entry.get().strip()
        if not name:
            show_center_messagebox("输入提示", "任务名称不能为空!")
            return

        try:
            hour = int(self.hour_entry.get())
            minute = int(self.minute_entry.get())
            second = int(self.second_entry.get())
            total_seconds = hour * 3600 + minute * 60 + second
            if total_seconds <= 0:
                show_center_messagebox("输入提示", "总时长必须大于0秒!")
                return
        except ValueError:
            show_center_messagebox("输入提示", "时/分/秒必须输入有效数字!")
            return

        # 2. 创建任务行(带边框)
        task_row = ttk.Frame(self.scrollable_frame, style="Countdown.TFrame")
        task_row.pack(fill=tk.X, pady=0, ipady=8, padx=0)

        # 创建内部框架来控制布局
        inner_frame = ttk.Frame(task_row, style="Countdown.TFrame")
        inner_frame.pack(fill=tk.X, expand=True, padx=5)
        
        # 配置三列布局,使用固定宽度
        inner_frame.columnconfigure(0, minsize=400)  # 任务名称固定宽度
        inner_frame.columnconfigure(1, minsize=150)  # 时间固定宽度
        inner_frame.columnconfigure(2, minsize=200)  # 按钮区固定宽度
        inner_frame.rowconfigure(0, weight=1)  # 行占满高度

        # 任务名称 - 添加[倒计提醒]前缀
        name_label = ttk.Label(inner_frame, text=f"[倒计提醒] {name}", style="Countdown.TLabel", anchor=tk.W, width=30)
        name_label.grid(row=0, column=0, sticky="w", padx=5)

        # 剩余时间 - 与表头对齐(居中)
        remaining_label = ttk.Label(inner_frame, text=self.format_time(total_seconds), style="Countdown.TLabel", anchor=tk.CENTER, width=10)
        remaining_label.grid(row=0, column=1, sticky="we", padx=5)

        # 3. 存储任务信息
        import datetime
        target_time = datetime.datetime.now() + datetime.timedelta(seconds=total_seconds)
        task_info = {
            "name": name,
            "total_seconds": total_seconds,
            "remaining_seconds": total_seconds,
            "target_time": target_time,
            "thread": None,
            "label": remaining_label,
            "row": task_row,
            "running": True
        }
        self.countdown_tasks.append(task_info)

        # 按钮区框架
        button_frame = ttk.Frame(inner_frame, style="Countdown.TFrame")
        button_frame.grid(row=0, column=2, sticky="we", padx=5)
        
        # 删除按钮
        delete_btn = ttk.Button(button_frame, text="删除", command=lambda r=task_row, info=task_info: self.delete_countdown(r, info), width=10)
        delete_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
        
        # 复制按钮
        copy_btn = ttk.Button(button_frame, text="复制", command=lambda info=task_info: self.copy_task(info), width=10, style="Copy.TButton")
        copy_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)

        # 任务将由 update_tasks 方法统一处理

        # 清空输入框(恢复默认名称)
        self.name_entry.delete(0, tk.END)
        self.name_entry.insert(0, "我的倒计提醒")
        self.hour_entry.delete(0, tk.END)
        self.hour_entry.insert(0, "0")
        self.minute_entry.delete(0, tk.END)
        self.minute_entry.insert(0, "0")
        self.second_entry.delete(0, tk.END)
        self.second_entry.insert(0, "10")

    def update_tasks(self):
        """统一更新所有任务的状态"""
        try:
            current_time = time.time()
            
            # 处理倒计时任务
            for task_info in self.countdown_tasks:
                if task_info["running"] and task_info["remaining_seconds"] > 0:
                    task_info["remaining_seconds"] -= 0.1  # 小步更新,提高平滑度
                    if task_info["remaining_seconds"] <= 0:
                        task_info["remaining_seconds"] = 0
                        # 任务完成,显示提醒
                        self.update_time_label(task_info, finished=True)
                        self.show_alert(task_info["name"], task_type="countdown", task_info=task_info)
                    else:
                        # 只在需要时更新UI
                        if "last_update" in task_info:
                            if current_time - task_info["last_update"] >= 0.5:
                                self.update_time_label(task_info)
                                task_info["last_update"] = current_time
                        else:
                            self.update_time_label(task_info)
                            task_info["last_update"] = current_time
            
            # 处理提醒任务
            for reminder_info in self.reminder_tasks:
                if reminder_info["running"] and reminder_info["remaining_seconds"] > 0:
                    reminder_info["remaining_seconds"] -= 0.1  # 小步更新,提高平滑度
                    if reminder_info["remaining_seconds"] <= 0:
                        reminder_info["remaining_seconds"] = 0
                        # 任务完成,显示提醒
                        self.update_time_label(reminder_info, finished=True)
                        self.show_alert(reminder_info["name"], task_type="reminder", task_info=reminder_info)
                    else:
                        # 只在需要时更新UI
                        if "last_update" in reminder_info:
                            if current_time - reminder_info["last_update"] >= 0.5:
                                self.update_time_label(reminder_info)
                                reminder_info["last_update"] = current_time
                        else:
                            self.update_time_label(reminder_info)
                            reminder_info["last_update"] = current_time
        except Exception as e:
            print(f"更新任务失败: {e}")
        finally:
            # 继续下一次更新
            self.root.after(100, self.update_tasks)  # 100ms更新一次,平衡性能和流畅度
    
    def delete_reminder(self, task_row, reminder_info):
        """删除提醒任务"""
        # 停止任务线程
        reminder_info["running"] = False
        # 销毁任务行
        task_row.destroy()
        # 从任务列表中移除
        if reminder_info in self.reminder_tasks:
            self.reminder_tasks.remove(reminder_info)
        # 更新滚动区域
        self.update_scrollable_frame()
    
    def copy_reminder(self, reminder_info):
        """复制定时提醒任务"""
        # 创建复制对话框
        copy_window = tk.Toplevel(self.root)
        copy_window.title("复制定时提醒")
        copy_window.resizable(False, False)
        copy_window.transient(self.root)
        copy_window.grab_set()
        
        # 设置窗口大小和位置
        window_width = 500
        window_height = 250
        screen_width = copy_window.winfo_screenwidth()
        screen_height = copy_window.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        copy_window.geometry(f"{window_width}x{window_height}+{x}+{y}")
        copy_window.configure(bg="#ffffff")
        
        # 创建内容框架
        content_frame = ttk.Frame(copy_window, padding=20)
        content_frame.pack(fill=tk.BOTH, expand=True)
        
        # 配置列权重,使内容居中
        content_frame.columnconfigure(0, weight=1)
        content_frame.columnconfigure(1, weight=0)
        content_frame.columnconfigure(2, weight=1)
        
        # 任务名称输入 - 居中显示
        ttk.Label(content_frame, text="提醒名称:", style="Task.TLabel").grid(row=0, column=0, padx=5, pady=10, sticky=tk.E)
        name_var = tk.StringVar(value=reminder_info["name"])
        name_entry = ttk.Entry(content_frame, textvariable=name_var, width=20)
        name_entry.grid(row=0, column=1, padx=5, pady=10, sticky=tk.W)
        ttk.Label(content_frame, text="", style="Task.TLabel").grid(row=0, column=2, padx=5, pady=10)
        
        # 时间选择 - 居中显示
        ttk.Label(content_frame, text="提醒时间:", style="Task.TLabel").grid(row=1, column=0, padx=5, pady=10, sticky=tk.E)
        
        # 时间选择框架
        time_frame = ttk.Frame(content_frame)
        time_frame.grid(row=1, column=1, padx=5, pady=10, sticky=tk.W)
        
        # 获取当前时间
        import datetime
        if "target_time" in reminder_info:
            target_time = reminder_info["target_time"]
        else:
            target_time = datetime.datetime.now() + datetime.timedelta(seconds=30)
        
        # 时间部分(只显示时分秒)
        hour_var = tk.StringVar(value=f"{target_time.hour:02d}")
        hour_entry = ttk.Combobox(time_frame, textvariable=hour_var, width=3, values=[f"{i:02d}" for i in range(24)])
        hour_entry.pack(side=tk.LEFT, padx=1)
        ttk.Label(time_frame, text="时", style="Task.TLabel").pack(side=tk.LEFT, padx=0)
        
        minute_var = tk.StringVar(value=f"{target_time.minute:02d}")
        minute_entry = ttk.Combobox(time_frame, textvariable=minute_var, width=3, values=[f"{i:02d}" for i in range(60)])
        minute_entry.pack(side=tk.LEFT, padx=1)
        ttk.Label(time_frame, text="分", style="Task.TLabel").pack(side=tk.LEFT, padx=1)
        
        second_var = tk.StringVar(value=f"{target_time.second:02d}")
        second_entry = ttk.Combobox(time_frame, textvariable=second_var, width=3, values=[f"{i:02d}" for i in range(60)])
        second_entry.pack(side=tk.LEFT, padx=1)
        ttk.Label(time_frame, text="秒", style="Task.TLabel").pack(side=tk.LEFT, padx=1)
        
        ttk.Label(content_frame, text="", style="Task.TLabel").grid(row=1, column=2, padx=5, pady=10)
        
        # 按钮框架 - 居中显示
        button_frame = ttk.Frame(content_frame)
        button_frame.grid(row=2, column=0, columnspan=3, pady=20)
        
        # 确定按钮
        def on_ok():
            # 检查任务数量限制
            total_tasks = len(self.countdown_tasks) + len(self.reminder_tasks)
            if total_tasks >= 10:
                show_center_messagebox("任务数量限制", "当前任务列表最多只能添加10条任务,请先删除部分任务后再添加!")
                copy_window.destroy()
                return
            
            # 验证输入
            task_name = name_var.get().strip()
            if not task_name:
                show_center_messagebox("输入提示", "提醒名称不能为空!")
                return
            
            try:
                # 获取当前日期
                current_date = datetime.datetime.now()
                year = current_date.year
                month = current_date.month
                day = current_date.day
                
                # 获取选择的时间
                hour = int(hour_var.get())
                minute = int(minute_var.get())
                second = int(second_var.get())
                
                # 计算目标时间
                target_time = datetime.datetime(year, month, day, hour, minute, second)
                current_time = datetime.datetime.now()
                
                # 计算时间差(秒)
                time_diff = (target_time - current_time).total_seconds()
                
                if time_diff <= 0:
                    show_center_messagebox("输入提示", "提醒时间必须在当前时间之后!")
                    return
                    
            except ValueError:
                show_center_messagebox("输入提示", "请输入有效的日期时间!")
                return
            
            # 创建新的定时提醒任务
            # 2. 创建任务行
            task_row = ttk.Frame(self.scrollable_frame, style="Reminder.TFrame")
            task_row.pack(fill=tk.X, pady=0, ipady=8, padx=0)
            
            # 创建内部框架来控制布局
            inner_frame = ttk.Frame(task_row, style="Reminder.TFrame")
            inner_frame.pack(fill=tk.X, expand=True, padx=5)
            
            # 配置三列布局,使用固定宽度
            inner_frame.columnconfigure(0, minsize=400)  # 任务名称固定宽度
            inner_frame.columnconfigure(1, minsize=150)  # 时间固定宽度
            inner_frame.columnconfigure(2, minsize=200)  # 按钮区固定宽度
            inner_frame.rowconfigure(0, weight=1)  # 行占满高度
            
            # 任务名称(标记为提醒) - 与表头对齐,使用ellipsis处理长文本
            name_label = ttk.Label(inner_frame, text=f"[定时提醒] {task_name}", style="Reminder.TLabel", anchor=tk.W, width=30, )
            name_label.grid(row=0, column=0, sticky="w", padx=5)
            
            # 剩余时间 - 与表头对齐(居中)
            remaining_label = ttk.Label(inner_frame, text=self.format_time(int(time_diff)), style="Reminder.TLabel", anchor=tk.CENTER, width=10)
            remaining_label.grid(row=0, column=1, sticky="we", padx=5)
            
            # 3. 存储任务信息
            new_reminder_info = {
                "name": task_name,
                "target_time": target_time,
                "remaining_seconds": int(time_diff),
                "thread": None,
                "label": remaining_label,
                "row": task_row,
                "running": True
            }
            self.reminder_tasks.append(new_reminder_info)
            
            # 按钮区框架
            button_frame = ttk.Frame(inner_frame, style="Reminder.TFrame")
            button_frame.grid(row=0, column=2, sticky="we", padx=5)
            
            # 删除按钮
            delete_btn = ttk.Button(button_frame, text="删除", command=lambda r=task_row, info=new_reminder_info: self.delete_reminder(r, info), width=10)
            delete_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
            
            # 复制按钮
            copy_btn = ttk.Button(button_frame, text="复制", command=lambda info=new_reminder_info: self.copy_reminder(info), width=10, style="Copy.TButton")
            copy_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
            
            # 任务将由 update_tasks 方法统一处理
            
            # 关闭对话框
            copy_window.destroy()
        
        # 取消按钮
        def on_cancel():
            copy_window.destroy()
        
        # 按钮
        ok_button = ttk.Button(button_frame, text="确定", command=on_ok, width=10)
        ok_button.pack(side=tk.LEFT, padx=10)
        cancel_button = ttk.Button(button_frame, text="取消", command=on_cancel, width=10)
        cancel_button.pack(side=tk.LEFT, padx=10)

    def update_time_label(self, task_info, finished=False):
        """更新剩余时间显示"""
        # 检查任务是否仍在运行,避免更新已删除任务的标签
        if not task_info.get("running"):
            return
        
        try:
            # 根据任务类型选择正确的样式
            task_type = "Countdown"
            if "target_time" in task_info:
                task_type = "Reminder"
            
            if finished:
                # 保持标签的背景色与任务类型一致
                task_info["label"].config(text="&#9989; 时间到!", foreground="#dc2626")
            else:
                task_info["label"].config(text=self.format_time(task_info["remaining_seconds"]), style=f"{task_type}.TLabel")
        except tk.TclError:
            # 标签已被销毁,忽略错误
            pass

    def format_time(self, seconds):
        """格式化时间为 00:00:00"""
        # 将浮点数转换为整数
        seconds = int(seconds)
        h = seconds // 3600
        m = (seconds % 3600) // 60
        s = seconds % 60
        return f"{h:02d}:{m:02d}:{s:02d}"

    def delete_countdown(self, task_row, task_info):
        """删除倒计时任务"""
        # 停止任务线程
        task_info["running"] = False
        # 销毁任务行
        task_row.destroy()
        # 从任务列表中移除
        if task_info in self.countdown_tasks:
            self.countdown_tasks.remove(task_info)
        # 更新滚动区域
        self.update_scrollable_frame()
    
    def copy_task(self, task_info):
        """复制任务"""
        # 创建复制对话框
        copy_window = tk.Toplevel(self.root)
        copy_window.title("复制任务")
        copy_window.resizable(False, False)
        copy_window.transient(self.root)
        copy_window.grab_set()
        
        # 设置窗口大小和位置
        window_width = 400
        window_height = 200
        screen_width = copy_window.winfo_screenwidth()
        screen_height = copy_window.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        copy_window.geometry(f"{window_width}x{window_height}+{x}+{y}")
        copy_window.configure(bg="#ffffff")
        
        # 创建内容框架
        content_frame = ttk.Frame(copy_window, padding=20)
        content_frame.pack(fill=tk.BOTH, expand=True)
        
        # 配置列权重,使内容居中
        content_frame.columnconfigure(0, weight=1)
        content_frame.columnconfigure(1, weight=0)
        content_frame.columnconfigure(2, weight=1)
        
        # 任务名称输入 - 居中显示
        ttk.Label(content_frame, text="任务名称:", style="Task.TLabel").grid(row=0, column=0, padx=5, pady=10, sticky=tk.E)
        name_var = tk.StringVar(value=task_info["name"])
        name_entry = ttk.Entry(content_frame, textvariable=name_var, width=20)
        name_entry.grid(row=0, column=1, padx=5, pady=10, sticky=tk.W)
        ttk.Label(content_frame, text="", style="Task.TLabel").grid(row=0, column=2, padx=5, pady=10)
        
        # 倒计时时长输入 - 居中显示
        ttk.Label(content_frame, text="倒计时时长:", style="Task.TLabel").grid(row=1, column=0, padx=5, pady=10, sticky=tk.E)
        
        # 时长输入框架
        time_frame = ttk.Frame(content_frame)
        time_frame.grid(row=1, column=1, padx=5, pady=10, sticky=tk.W)
        
        # 获取当前时长
        duration = task_info["total_seconds"]
        hours = duration // 3600
        minutes = (duration % 3600) // 60
        seconds = duration % 60
        
        # 小时输入
        hour_var = tk.StringVar(value=str(hours))
        hour_entry = ttk.Entry(time_frame, textvariable=hour_var, width=6)
        hour_entry.pack(side=tk.LEFT, padx=2)
        ttk.Label(time_frame, text="时", style="Task.TLabel").pack(side=tk.LEFT, padx=2)
        
        # 分钟输入
        minute_var = tk.StringVar(value=str(minutes))
        minute_entry = ttk.Entry(time_frame, textvariable=minute_var, width=6)
        minute_entry.pack(side=tk.LEFT, padx=2)
        ttk.Label(time_frame, text="分", style="Task.TLabel").pack(side=tk.LEFT, padx=2)
        
        # 秒输入
        second_var = tk.StringVar(value=str(seconds))
        second_entry = ttk.Entry(time_frame, textvariable=second_var, width=6)
        second_entry.pack(side=tk.LEFT, padx=2)
        ttk.Label(time_frame, text="秒", style="Task.TLabel").pack(side=tk.LEFT, padx=2)
        
        ttk.Label(content_frame, text="", style="Task.TLabel").grid(row=1, column=2, padx=5, pady=10)
        
        # 按钮框架 - 居中显示
        button_frame = ttk.Frame(content_frame)
        button_frame.grid(row=2, column=0, columnspan=3, pady=20)
        
        # 确定按钮
        def on_ok():
            # 检查任务数量限制
            total_tasks = len(self.countdown_tasks) + len(self.reminder_tasks)
            if total_tasks >= 10:
                show_center_messagebox("任务数量限制", "当前任务列表最多只能添加10条任务,请先删除部分任务后再添加!")
                copy_window.destroy()
                return
            
            # 验证输入
            task_name = name_var.get().strip()
            if not task_name:
                show_center_messagebox("输入提示", "任务名称不能为空!")
                return
            
            try:
                hours = int(hour_var.get())
                minutes = int(minute_var.get())
                seconds = int(second_var.get())
                total_seconds = hours * 3600 + minutes * 60 + seconds
                if total_seconds <= 0:
                    show_center_messagebox("输入提示", "总时长必须大于0秒!")
                    return
            except ValueError:
                show_center_messagebox("输入提示", "时/分/秒必须输入有效数字!")
                return
            
            # 创建新的倒计时任务
            # 2. 创建任务行(带边框)
            task_row = ttk.Frame(self.scrollable_frame, style="Countdown.TFrame")
            task_row.pack(fill=tk.X, pady=0, ipady=8, padx=0)

            # 创建内部框架来控制布局
            inner_frame = ttk.Frame(task_row, style="Countdown.TFrame")
            inner_frame.pack(fill=tk.X, expand=True, padx=5)
            
            # 配置三列布局,使用固定宽度
            inner_frame.columnconfigure(0, minsize=400)  # 任务名称固定宽度
            inner_frame.columnconfigure(1, minsize=150)  # 时间固定宽度
            inner_frame.columnconfigure(2, minsize=200)  # 按钮区固定宽度
            inner_frame.rowconfigure(0, weight=1)  # 行占满高度

            # 任务名称 - 添加[倒计提醒]前缀,使用ellipsis处理长文本
            name_label = ttk.Label(inner_frame, text=f"[倒计提醒] {task_name}", style="Countdown.TLabel", anchor=tk.W, width=30, )
            name_label.grid(row=0, column=0, sticky="w", padx=5)

            # 剩余时间 - 与表头对齐(居中)
            remaining_label = ttk.Label(inner_frame, text=self.format_time(total_seconds), style="Countdown.TLabel", anchor=tk.CENTER, width=10)
            remaining_label.grid(row=0, column=1, sticky="we", padx=5)

            # 存储任务信息
            import datetime
            target_time = datetime.datetime.now() + datetime.timedelta(seconds=total_seconds)
            new_task_info = {
                "name": task_name,
                "total_seconds": total_seconds,
                "remaining_seconds": total_seconds,
                "target_time": target_time,
                "thread": None,
                "label": remaining_label,
                "row": task_row,
                "running": True
            }
            self.countdown_tasks.append(new_task_info)

            # 按钮区框架
            button_frame = ttk.Frame(inner_frame, style="Countdown.TFrame")
            button_frame.grid(row=0, column=2, sticky="we", padx=5)
            
            # 删除按钮
            delete_btn = ttk.Button(button_frame, text="删除", command=lambda r=task_row, info=new_task_info: self.delete_countdown(r, info), width=10)
            delete_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
            
            # 复制按钮
            copy_btn = ttk.Button(button_frame, text="复制", command=lambda info=new_task_info: self.copy_task(info), width=10, style="Copy.TButton")
            copy_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)

            # 任务将由 update_tasks 方法统一处理
            
            # 关闭对话框
            copy_window.destroy()
        
        # 取消按钮
        def on_cancel():
            copy_window.destroy()
        
        # 按钮
        ok_button = ttk.Button(button_frame, text="确定", command=on_ok, width=10)
        ok_button.pack(side=tk.LEFT, padx=10)
        cancel_button = ttk.Button(button_frame, text="取消", command=on_cancel, width=10)
        cancel_button.pack(side=tk.LEFT, padx=10)
    
    def copy_task_from_alert(self, task_info, task_type):
        """从提醒窗口复制任务"""
        if task_type == "countdown":
            # 复制倒计时任务
            self.copy_task(task_info)
        else:
            # 复制提醒任务
            self.copy_reminder(task_info)
    
    def add_reminder(self):
        """添加定时提醒任务"""
        # 检查任务数量限制
        total_tasks = len(self.countdown_tasks) + len(self.reminder_tasks)
        if total_tasks >= 10:
            show_center_messagebox("任务数量限制", "当前任务列表最多只能添加10条任务,请先删除部分任务后再添加!")
            return
        
        # 1. 输入验证
        name = self.reminder_name_entry.get().strip()
        if not name:
            show_center_messagebox("输入提示", "提醒名称不能为空!")
            return
        
        try:
            # 获取选择的日期时间
            year = int(self.reminder_year.get())
            month = int(self.reminder_month.get())
            day = int(self.reminder_day.get())
            hour = int(self.reminder_hour.get())
            minute = int(self.reminder_minute.get())
            second = int(self.reminder_second.get())
            
            # 计算目标时间
            import datetime
            target_time = datetime.datetime(year, month, day, hour, minute, second)
            current_time = datetime.datetime.now()
            
            # 计算时间差(秒)
            time_diff = (target_time - current_time).total_seconds()
            
            if time_diff <= 0:
                show_center_messagebox("输入提示", "提醒时间必须在当前时间之后!")
                return
                
        except ValueError:
            show_center_messagebox("输入提示", "请输入有效的日期时间!")
            return
        
        # 2. 创建任务行
        task_row = ttk.Frame(self.scrollable_frame, style="Reminder.TFrame")
        task_row.pack(fill=tk.X, pady=0, ipady=8, padx=0)
        
        # 创建内部框架来控制布局
        inner_frame = ttk.Frame(task_row, style="Reminder.TFrame")
        inner_frame.pack(fill=tk.X, expand=True, padx=5)
        
        # 配置三列布局,使用固定宽度
        inner_frame.columnconfigure(0, minsize=400)  # 任务名称固定宽度
        inner_frame.columnconfigure(1, minsize=150)  # 时间固定宽度
        inner_frame.columnconfigure(2, minsize=200)  # 按钮区固定宽度
        inner_frame.rowconfigure(0, weight=1)  # 行占满高度
        
        # 任务名称(标记为提醒) - 与表头对齐
        name_label = ttk.Label(inner_frame, text=f"[定时提醒] {name}", style="Reminder.TLabel", anchor=tk.W, width=30)
        name_label.grid(row=0, column=0, sticky="w", padx=5)
        
        # 剩余时间 - 与表头对齐(居中)
        remaining_label = ttk.Label(inner_frame, text=self.format_time(int(time_diff)), style="Reminder.TLabel", anchor=tk.CENTER, width=10)
        remaining_label.grid(row=0, column=1, sticky="we", padx=5)
        
        # 3. 存储任务信息
        reminder_info = {
            "name": name,
            "target_time": target_time,
            "remaining_seconds": int(time_diff),
            "thread": None,
            "label": remaining_label,
            "row": task_row,
            "running": True
        }
        self.reminder_tasks.append(reminder_info)
        
        # 按钮区框架
        button_frame = ttk.Frame(inner_frame, style="Reminder.TFrame")
        button_frame.grid(row=0, column=2, sticky="we", padx=5)
        
        # 删除按钮
        delete_btn = ttk.Button(button_frame, text="删除", command=lambda r=task_row, info=reminder_info: self.delete_reminder(r, info), width=10)
        delete_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
        
        # 复制按钮
        copy_btn = ttk.Button(button_frame, text="复制", command=lambda info=reminder_info: self.copy_reminder(info), width=10, style="Copy.TButton")
        copy_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
        
        # 任务将由 update_tasks 方法统一处理
        
        # 清空输入框(恢复默认名称)
        self.reminder_name_entry.delete(0, tk.END)
        self.reminder_name_entry.insert(0, "我的定时提醒")

    def show_alert(self, task_name, task_type="countdown", task_info=None):
        """右下角滑入提醒窗口(优化样式)"""
        # 根据任务类型设置颜色
        if task_type == "reminder":
            bg_color = "#22c55e"  # 绿色,用于定时提醒
            title_text = "&#128276; 定时提醒"
        else:
            bg_color = "#3b82f6"  # 蓝色,用于倒计时
            title_text = "&#9200; 倒计时结束"

        # 创建提醒窗口
        alert_win = tk.Toplevel(self.root)
        alert_win.title("提醒")
        alert_win.overrideredirect(True)
        alert_win.geometry("320x160")
        alert_win.configure(bg=bg_color)

        # 提醒内容布局
        content_frame = tk.Frame(alert_win, bg=bg_color)
        content_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 标题
        title_label = tk.Label(content_frame, text=title_text, 
                               font=("Microsoft YaHei", 14, "bold"), 
                               bg=bg_color, fg="white")
        title_label.pack(pady=(5, 10))

        # 任务名称
        task_label = tk.Label(content_frame, text=f"任务:{task_name}", 
                              font=("Microsoft YaHei", 12), 
                              bg=bg_color, fg="white")
        task_label.pack(pady=5)

        # 关闭按钮
        close_btn = ttk.Button(content_frame, text="关闭", 
                               command=lambda: self.close_alert(alert_win, task_info, task_type))
        close_btn.pack(pady=(10, 5))

        # 计算位置(右下角滑入,实现层叠效果)
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        win_width = 320
        win_height = 160
        target_x = screen_width - win_width - 30
        # 计算垂直偏移量,实现层叠效果
        target_y = screen_height - win_height - 30 - (len(self.alert_windows) * 20)
        start_x = screen_width

        # 滑入动画
        def slide_in(current_x):
            if current_x > target_x:
                new_x = current_x - 8
                alert_win.geometry(f"{win_width}x{win_height}+{new_x}+{target_y}")
                alert_win.after(15, slide_in, new_x)
            else:
                alert_win.geometry(f"{win_width}x{win_height}+{target_x}+{target_y}")
                # 动画完成后将提醒窗口置于顶层
                alert_win.lift()
                alert_win.focus_force()
                alert_win.attributes('-topmost', True)  # 置于顶层
                alert_win.update()
                alert_win.attributes('-topmost', False)  # 取消顶层设置,避免一直置顶

        slide_in(start_x)
        
        # 将提醒窗口添加到列表中
        self.alert_windows.append(alert_win)
        


    def close_alert(self, alert_win, task_info=None, task_type=None):
        """关闭提醒窗口"""
        try:
            alert_win.destroy()
            # 从提醒窗口列表中移除
            if alert_win in self.alert_windows:
                self.alert_windows.remove(alert_win)
            
            # 如果有任务信息,提供复制任务的选项
            if task_info and task_type:
                # 延迟显示复制对话框,避免事件处理冲突
                self.root.after(100, lambda: self.copy_task_from_alert(task_info, task_type))
                # 延迟移除任务,确保复制操作完成
                self.root.after(500, lambda: self.remove_completed_task(task_info, task_type))
            
            # 显示主窗口
            self.show_window()
        except Exception as e:
            print(f"关闭提醒窗口失败: {e}")
    
    def update_scrollable_frame(self):
        """更新滚动区域,确保删除任务后没有残留背景色"""
        # 取消之前的更新请求,避免累积
        if hasattr(self, '_scroll_update_id'):
            self.root.after_cancel(self._scroll_update_id)
        # 延迟更新滚动区域,避免频繁更新
        self._scroll_update_id = self.root.after(100, self._do_update_scrollable_frame)

    def _do_update_scrollable_frame(self):
        """实际执行滚动区域更新"""
        try:
            self.scrollable_frame.update_idletasks()
            self.task_canvas.configure(scrollregion=self.task_canvas.bbox("all"))
        except Exception as e:
            print(f"更新滚动区域失败: {e}")

    def init_tray_icon(self):
        """延迟初始化托盘图标"""
        pass  # 托盘图标将在需要时创建

    def create_tray_icon(self):
        """创建托盘图标"""
        try:
            # 尝试使用 favicon.ico 作为托盘图标
            import os
            import sys
            
            # 获取应用程序运行目录
            if getattr(sys, 'frozen', False):
                # 打包后的环境
                if hasattr(sys, '_MEIPASS'):
                    # 使用 PyInstaller 的临时目录
                    script_dir = sys._MEIPASS
                else:
                    # 回退到可执行文件目录
                    script_dir = os.path.dirname(sys.executable)
            else:
                # 开发环境
                script_dir = os.path.dirname(os.path.abspath(__file__))
            
            icon_path = os.path.join(script_dir, 'favicon.ico')
            
            if os.path.exists(icon_path):
                try:
                    # 使用现有图标
                    image = Image.open(icon_path)
                except Exception:
                    # 创建一个简单的图标作为备用
                    image = Image.new('RGB', (64, 64), color='#3b82f6')
                    draw = ImageDraw.Draw(image)
                    draw.text((15, 15), "&#9200;", font=None, fill='white')
            else:
                # 创建一个简单的图标作为备用
                image = Image.new('RGB', (64, 64), color='#3b82f6')
                draw = ImageDraw.Draw(image)
                draw.text((15, 15), "&#9200;", font=None, fill='white')
            
            # 创建托盘菜单
            menu = pystray.Menu(
                pystray.MenuItem("显示窗口", self.show_window),
                pystray.MenuItem("显示悬浮窗", self.create_floating_window),
                pystray.MenuItem("退出", self.exit_app)
            )
            
            # 创建托盘图标
            self.tray_icon = pystray.Icon("countdown_app", image, "多任务倒计时工具", menu)
            
            # 启动托盘图标在单独的线程中
            def run_tray():
                try:
                    # 运行托盘图标
                    self.tray_icon.run()
                except Exception:
                    pass
                finally:
                    # 托盘图标停止后释放资源
                    if self.tray_icon:
                        self.tray_icon = None
            
            # 启动托盘图标线程
            tray_thread = threading.Thread(target=run_tray, daemon=True)
            tray_thread.start()
        except Exception:
            pass

    def on_minimize(self, event):
        """处理窗口最小化事件"""
        # 检查是否是最小化事件
        if event.widget == self.root and event.type == tk.EventType.Unmap:
            # 隐藏窗口
            self.root.withdraw()
            # 创建并显示托盘图标
            if not self.tray_icon:
                # 直接创建托盘图标
                self.create_tray_icon()

    def on_close(self):
        """处理窗口关闭事件,最小化到托盘"""
        # 隐藏窗口
        self.root.withdraw()
        # 创建并显示托盘图标
        if not self.tray_icon:
            # 直接创建托盘图标
            self.create_tray_icon()

    def show_window(self):
        """从托盘恢复窗口"""
        try:
            # 显示窗口
            self.root.deiconify()
            # 激活窗口并置于顶层
            self.root.lift()
            self.root.focus_force()
            self.root.attributes('-topmost', True)  # 置于顶层
            self.root.update()
            self.root.attributes('-topmost', False)  # 取消顶层设置,避免一直置顶
            # 隐藏悬浮窗
            self.hide_floating_window()
            # 停止托盘图标
            if self.tray_icon:
                try:
                    self.tray_icon.stop()
                except Exception as e:
                    print(f"停止托盘图标失败: {e}")
                finally:
                    self.tray_icon = None
        except Exception as e:
            print(f"显示窗口失败: {e}")
    
    def create_floating_window(self):
        """创建独立的悬浮窗窗口,彻底解决闪烁问题"""
        try:
            # 检查悬浮窗是否已存在
            if hasattr(self, 'floating_window') and self.floating_window.winfo_exists():
                # 如果已存在,显示并置于顶层
                self.floating_window.lift()
                self.floating_window.attributes('-topmost', True)
                self.floating_window.update()
                self.floating_window.attributes('-topmost', False)
                return
            
            # 先计算窗口位置
            window_width = 400
            window_height = 500
            screen_width = self.root.winfo_screenwidth()
            screen_height = self.root.winfo_screenheight()
            # 计算右下角位置,留出一些边距
            x = screen_width - window_width - 20
            y = screen_height - window_height - 80  # 留出任务栏高度
            
            # 创建一个Toplevel窗口作为悬浮窗
            # 使用更优化的方式避免闪烁问题
            self.floating_window = tk.Toplevel(self.root)
            # 先设置为隐藏状态
            self.floating_window.withdraw()
            # 设置窗口属性
            self.floating_window.title("任务列表")
            self.floating_window.overrideredirect(True)  # 无边框
            self.floating_window.attributes('-topmost', True)  # 置于顶层
            self.floating_window.attributes('-alpha', 0.95)  # 半透明效果
            
            # 直接在指定位置创建窗口
            self.floating_window.geometry(f"{window_width}x{window_height}+{x}+{y}")
            # 强制更新窗口位置和大小
            self.floating_window.update_idletasks()
            # 显示窗口
            self.floating_window.deiconify()
            
            # 亮色风格设计
            # 设置背景色为亮色
            self.floating_window.configure(bg="#ffffff")
            
            # 创建亮色风格的自定义样式
            floating_style = ttk.Style(self.floating_window)
            floating_style.theme_use("clam")
            
            # 标题标签样式
            floating_style.configure("Finance.Title.TLabel", 
                                  font=("Microsoft YaHei", 12, "bold"),
                                  foreground="#333333",
                                  background="#ffffff")
            
            # 隐藏按钮样式
            floating_style.configure("Finance.TButton", 
                                  font=("Microsoft YaHei", 10, "bold"),
                                  background="#f0f0f0",
                                  foreground="#333333",
                                  padding=6)
            floating_style.map("Finance.TButton",
                             background=[("active", "#e0e0e0")])
            
            # 创建主框架
            main_frame = ttk.Frame(self.floating_window)
            main_frame.pack(fill=tk.BOTH, expand=True, padx=2, pady=2)
            
            # 创建标题栏
            title_frame = ttk.Frame(main_frame)
            title_frame.pack(fill=tk.X, padx=10, pady=10)
            
            # 标题 - 金融风格字体
            title_label = ttk.Label(title_frame, text="多任务倒计时工具", style="Finance.Title.TLabel")
            title_label.pack(side=tk.LEFT, padx=5)
            
            # 隐藏按钮 - 金融风格,使用lambda确保正确调用
            hide_btn = ttk.Button(title_frame, text="隐藏", command=lambda: self.hide_floating_window(), width=8, style="Finance.TButton")
            hide_btn.pack(side=tk.RIGHT, padx=5)
            
            # 创建任务列表框架
            task_frame = ttk.Frame(main_frame)
            task_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10))
            
            # 创建任务列表,使用亮色风格样式
            self.task_listbox = tk.Listbox(
                task_frame, 
                font=("Microsoft YaHei", 12),  # 加大字体,使用微软雅黑
                selectbackground="#3b82f6", 
                selectforeground="white",
                bg="#f8f9fa",  # 亮色背景
                fg="#333333",  # 深色文字
                relief="flat",  # 平坦效果
                bd=0,
                highlightthickness=0,
                activestyle="none"
            )
            
            # 添加亮色风格的滚动条
            # 配置滚动条样式
            floating_style.configure("Finance.Vertical.TScrollbar",
                                  background="#e0e0e0",
                                  troughcolor="#f8f9fa",
                                  arrowcolor="#666666",
                                  bordercolor="#d0d0d0",
                                  relief="flat")
            
            scrollbar = ttk.Scrollbar(task_frame, orient=tk.VERTICAL, command=self.task_listbox.yview, style="Finance.Vertical.TScrollbar")
            scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
            self.task_listbox.config(yscrollcommand=scrollbar.set)
            
            # 调整任务列表的pack方式,确保滚动条正确显示
            self.task_listbox.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
            
            # 存储滚动条引用
            self.scrollbar = scrollbar
            
            # 更新任务列表
            self.update_task_list()
            
            # 显示窗口
            self.floating_window.deiconify()
            
            # 定时更新任务列表
            self.floating_window.after(1000, self.update_task_list)
            
        except Exception as e:
            print(f"创建悬浮窗失败: {e}")
    
    def update_task_list(self):
        """更新任务列表"""
        try:
            if not hasattr(self, 'task_listbox') or not self.task_listbox.winfo_exists():
                return
            
            # 清空列表
            self.task_listbox.delete(0, tk.END)
            
            # 计算任务总数
            total_tasks = len(self.countdown_tasks) + len(self.reminder_tasks)
            
            # 如果没有任务,显示提示信息
            if total_tasks == 0:
                self.task_listbox.insert(tk.END, "&#128203; 暂无任务")
                self.task_listbox.itemconfig(0, {'fg': '#999999'})  # 亮色风格灰色
            else:
                # 添加倒计时任务
                for task_info in self.countdown_tasks:
                    if task_info.get("running", False):
                        remaining = int(task_info.get("remaining_seconds", 0))
                        task_name = task_info.get("name", "未知任务")
                        status = f"&#9200; [倒计提醒] {task_name}"
                        time_str = f"剩余: {self.format_time(remaining)}"
                        # 使用任务对象中存储的target_time
                        target_time = task_info.get("target_time")
                        if target_time:
                            # 只显示时间部分,不显示日期
                            target_str = f"目标时间: {target_time.strftime('%H:%M:%S')}"
                        else:
                            # 如果没有target_time,使用当前时间 + 剩余秒数作为备用
                            import datetime
                            target_time = datetime.datetime.now() + datetime.timedelta(seconds=remaining)
                            target_str = f"目标时间: {target_time.strftime('%H:%M:%S')}"
                        self.task_listbox.insert(tk.END, status)
                        self.task_listbox.insert(tk.END, time_str)
                        self.task_listbox.insert(tk.END, target_str)
                        # 设置颜色 - 亮色风格
                        last_idx = self.task_listbox.size() - 1
                        self.task_listbox.itemconfig(last_idx - 2, {'fg': '#3b82f6'})  # 蓝色
                        self.task_listbox.itemconfig(last_idx - 1, {'fg': '#666666'})  # 灰色
                        self.task_listbox.itemconfig(last_idx, {'fg': '#999999'})  # 浅灰色
                        # 添加空行作为分隔
                        self.task_listbox.insert(tk.END, "")
                
                # 添加提醒任务
                for reminder_info in self.reminder_tasks:
                    if reminder_info.get("running", False):
                        remaining = int(reminder_info.get("remaining_seconds", 0))
                        task_name = reminder_info.get("name", "未知任务")
                        status = f"&#128276; [定时提醒] {task_name}"
                        time_str = f"剩余: {self.format_time(remaining)}"
                        # 获取目标时间
                        import datetime
                        target_time = reminder_info.get("target_time", datetime.datetime.now())
                        # 只显示时间部分,不显示日期
                        target_str = f"目标时间: {target_time.strftime('%H:%M:%S')}"
                        self.task_listbox.insert(tk.END, status)
                        self.task_listbox.insert(tk.END, time_str)
                        self.task_listbox.insert(tk.END, target_str)
                        # 设置颜色 - 亮色风格
                        last_idx = self.task_listbox.size() - 1
                        self.task_listbox.itemconfig(last_idx - 2, {'fg': '#22c55e'})  # 绿色
                        self.task_listbox.itemconfig(last_idx - 1, {'fg': '#666666'})  # 灰色
                        self.task_listbox.itemconfig(last_idx, {'fg': '#999999'})  # 浅灰色
                        # 添加空行作为分隔
                        self.task_listbox.insert(tk.END, "")
            
            # 自动显示/隐藏滚动条
            if hasattr(self, 'scrollbar'):
                try:
                    # 检查任务列表是否需要滚动
                    self.task_listbox.update_idletasks()
                    if self.task_listbox.winfo_exists():
                        # 获取任务列表的高度和内容高度
                        listbox_height = self.task_listbox.winfo_height()
                        content_height = self.task_listbox.bbox(tk.END)[3] if self.task_listbox.size() > 0 else 0
                        
                        # 如果内容高度大于列表框高度,显示滚动条
                        if content_height > listbox_height:
                            if not self.scrollbar.winfo_ismapped():
                                self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
                        else:
                            # 否则隐藏滚动条
                            if self.scrollbar.winfo_ismapped():
                                self.scrollbar.pack_forget()
                except Exception as e:
                    print(f"调整滚动条失败: {e}")
            
            # 再次定时更新
            if hasattr(self, 'floating_window') and self.floating_window.winfo_exists():
                self.floating_window.after(1000, self.update_task_list)
        except Exception as e:
            print(f"更新任务列表失败: {e}")
    
    def hide_floating_window(self):
        """隐藏悬浮窗"""
        try:
            if hasattr(self, 'floating_window') and self.floating_window.winfo_exists():
                self.floating_window.destroy()
                delattr(self, 'floating_window')
        except Exception as e:
            print(f"隐藏悬浮窗失败: {e}")





    def remove_completed_task(self, task_info, task_type):
        """移除已完成的任务,释放内存"""
        try:
            # 从相应的任务列表中移除
            if task_type == "countdown" and task_info in self.countdown_tasks:
                self.countdown_tasks.remove(task_info)
            elif task_type == "reminder" and task_info in self.reminder_tasks:
                self.reminder_tasks.remove(task_info)
            
            # 销毁任务行
            if "row" in task_info:
                try:
                    task_info["row"].destroy()
                except Exception as e:
                    print(f"销毁任务行失败: {e}")
                del task_info["row"]
            
            # 清理任务对象中的引用
            if "future" in task_info:
                del task_info["future"]
            if "label" in task_info:
                del task_info["label"]
            
            # 延迟更新滚动区域,确保任务移除操作完成后再更新
            self.root.after(300, self.update_scrollable_frame)
        except Exception as e:
            print(f"移除任务失败: {e}")

    def save_tasks(self):
        """保存任务存档"""
        try:
            # 获取存档文件路径
            if getattr(sys, 'frozen', False):
                # 在打包环境中,使用可执行文件所在的目录
                script_dir = os.path.dirname(sys.executable)
            else:
                script_dir = os.path.dirname(os.path.abspath(__file__))
            save_path = os.path.join(script_dir, 'tasks.json')
            
            # 收集任务信息
            tasks_data = {
                "countdown_tasks": [],
                "reminder_tasks": []
            }
            
            # 保存倒计时任务
            import datetime
            save_time = datetime.datetime.now()
            for task in self.countdown_tasks:
                if task.get("running", False) and task.get("remaining_seconds", 0) > 0:
                    task_data = {
                        "name": task.get("name"),
                        "total_seconds": task.get("total_seconds"),
                        "remaining_seconds": task.get("remaining_seconds"),
                        "type": "countdown",
                        "save_time": save_time.isoformat()
                    }
                    tasks_data["countdown_tasks"].append(task_data)
            
            # 保存提醒任务
            for task in self.reminder_tasks:
                if task.get("running", False) and task.get("remaining_seconds", 0) > 0:
                    task_data = {
                        "name": task.get("name"),
                        "target_time": task.get("target_time").isoformat() if "target_time" in task else None,
                        "remaining_seconds": task.get("remaining_seconds"),
                        "type": "reminder",
                        "save_time": save_time.isoformat()
                    }
                    tasks_data["reminder_tasks"].append(task_data)
            
            # 保存到文件
            with open(save_path, 'w', encoding='utf-8') as f:
                json.dump(tasks_data, f, ensure_ascii=False, indent=2)
            
        except Exception as e:
            print(f"保存任务失败: {e}")

    def load_tasks(self):
        """加载任务存档"""
        try:
            # 获取存档文件路径
            if getattr(sys, 'frozen', False):
                # 在打包环境中,使用可执行文件所在的目录
                script_dir = os.path.dirname(sys.executable)
            else:
                script_dir = os.path.dirname(os.path.abspath(__file__))
            save_path = os.path.join(script_dir, 'tasks.json')
            
            # 检查文件是否存在
            if not os.path.exists(save_path):
                return
            
            # 读取存档文件
            with open(save_path, 'r', encoding='utf-8') as f:
                tasks_data = json.load(f)
            
            # 加载倒计时任务
            import datetime
            current_time = datetime.datetime.now()
            
            for task_data in tasks_data.get("countdown_tasks", []):
                remaining_seconds = task_data.get("remaining_seconds", 0)
                save_time_str = task_data.get("save_time")
                
                # 计算实际剩余时间
                actual_remaining = remaining_seconds
                
                # 如果有保存时间,计算保存到现在的时间差
                if save_time_str:
                    try:
                        save_time = datetime.datetime.fromisoformat(save_time_str)
                        time_diff = (current_time - save_time).total_seconds()
                        # 减去保存到现在的时间差
                        actual_remaining = max(0, remaining_seconds - time_diff)
                    except Exception as e:
                        print(f"解析保存时间失败: {e}")
                
                # 检查是否超过10秒
                if actual_remaining <= 10:
                    actual_remaining = 0
                
                # 创建任务行
                task_row = ttk.Frame(self.scrollable_frame, style="Countdown.TFrame")
                task_row.pack(fill=tk.X, pady=0, ipady=8, padx=0)

                # 创建内部框架
                inner_frame = ttk.Frame(task_row, style="Countdown.TFrame")
                inner_frame.pack(fill=tk.X, expand=True, padx=5)
                
                # 配置布局
                inner_frame.columnconfigure(0, minsize=400)
                inner_frame.columnconfigure(1, minsize=150)
                inner_frame.columnconfigure(2, minsize=200)
                inner_frame.rowconfigure(0, weight=1)

                # 任务名称
                name_label = ttk.Label(inner_frame, text=f"[倒计提醒] {task_data.get('name')}", style="Countdown.TLabel", anchor=tk.W, width=30)
                name_label.grid(row=0, column=0, sticky="w", padx=5)

                # 检查是否已过期
                if actual_remaining <= 0:
                    # 已过期,显示时间到
                    remaining_label = ttk.Label(inner_frame, text="&#9989; 时间到!", style="Countdown.TLabel", anchor=tk.CENTER, width=10, foreground="#dc2626")
                    task_running = False
                else:
                    # 未过期,显示剩余时间
                    remaining_label = ttk.Label(inner_frame, text=self.format_time(actual_remaining), style="Countdown.TLabel", anchor=tk.CENTER, width=10)
                    task_running = True
                
                remaining_label.grid(row=0, column=1, sticky="we", padx=5)

                # 存储任务信息
                import datetime
                # 计算目标时间:当前时间 + 实际剩余时间
                target_time = datetime.datetime.now() + datetime.timedelta(seconds=actual_remaining)
                task_info = {
                    "name": task_data.get('name'),
                    "total_seconds": task_data.get('total_seconds'),
                    "remaining_seconds": actual_remaining,
                    "target_time": target_time,
                    "thread": None,
                    "label": remaining_label,
                    "row": task_row,
                    "running": task_running
                }
                self.countdown_tasks.append(task_info)

                # 按钮区
                button_frame = ttk.Frame(inner_frame, style="Countdown.TFrame")
                button_frame.grid(row=0, column=2, sticky="we", padx=5)
                
                # 删除按钮
                delete_btn = ttk.Button(button_frame, text="删除", command=lambda r=task_row, info=task_info: self.delete_countdown(r, info), width=10)
                delete_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
                
                # 复制按钮
                copy_btn = ttk.Button(button_frame, text="复制", command=lambda info=task_info: self.copy_task(info), width=10, style="Copy.TButton")
                copy_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
            
            # 加载提醒任务
            for task_data in tasks_data.get("reminder_tasks", []):
                # 计算实际剩余时间
                import datetime
                target_time = datetime.datetime.fromisoformat(task_data.get('target_time')) if task_data.get('target_time') else None
                actual_remaining = 0
                
                if target_time:
                    time_diff = (target_time - current_time).total_seconds()
                    actual_remaining = max(0, time_diff)
                
                # 检查是否超过10秒
                if actual_remaining <= 10:
                    actual_remaining = 0
                
                # 创建任务行
                task_row = ttk.Frame(self.scrollable_frame, style="Reminder.TFrame")
                task_row.pack(fill=tk.X, pady=0, ipady=8, padx=0)

                # 创建内部框架
                inner_frame = ttk.Frame(task_row, style="Reminder.TFrame")
                inner_frame.pack(fill=tk.X, expand=True, padx=5)
                
                # 配置布局
                inner_frame.columnconfigure(0, minsize=400)
                inner_frame.columnconfigure(1, minsize=150)
                inner_frame.columnconfigure(2, minsize=200)
                inner_frame.rowconfigure(0, weight=1)

                # 任务名称
                name_label = ttk.Label(inner_frame, text=f"[定时提醒] {task_data.get('name')}", style="Reminder.TLabel", anchor=tk.W, width=30)
                name_label.grid(row=0, column=0, sticky="w", padx=5)

                # 检查是否已过期
                if actual_remaining <= 0:
                    # 已过期,显示时间到
                    remaining_label = ttk.Label(inner_frame, text="&#9989; 时间到!", style="Reminder.TLabel", anchor=tk.CENTER, width=10, foreground="#dc2626")
                    task_running = False
                else:
                    # 未过期,显示剩余时间
                    remaining_label = ttk.Label(inner_frame, text=self.format_time(actual_remaining), style="Reminder.TLabel", anchor=tk.CENTER, width=10)
                    task_running = True
                
                remaining_label.grid(row=0, column=1, sticky="we", padx=5)

                # 存储任务信息
                task_info = {
                    "name": task_data.get('name'),
                    "target_time": target_time,
                    "remaining_seconds": actual_remaining,
                    "thread": None,
                    "label": remaining_label,
                    "row": task_row,
                    "running": task_running
                }
                self.reminder_tasks.append(task_info)

                # 按钮区
                button_frame = ttk.Frame(inner_frame, style="Reminder.TFrame")
                button_frame.grid(row=0, column=2, sticky="we", padx=5)
                
                # 删除按钮
                delete_btn = ttk.Button(button_frame, text="删除", command=lambda r=task_row, info=task_info: self.delete_reminder(r, info), width=10)
                delete_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
                
                # 复制按钮
                copy_btn = ttk.Button(button_frame, text="复制", command=lambda info=task_info: self.copy_reminder(info), width=10, style="Copy.TButton")
                copy_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
            
            # 更新滚动区域
            self.update_scrollable_frame()
            
        except Exception as e:
            print(f"加载任务失败: {e}")

    def exit_app(self):
        """从托盘退出应用"""
        # 保存任务存档
        self.save_tasks()
        # 停止所有任务
        for task in self.countdown_tasks:
            task["running"] = False
        for task in self.reminder_tasks:
            task["running"] = False
        # 关闭悬浮窗
        self.hide_floating_window()
        # 停止托盘图标
        if self.tray_icon:
            self.tray_icon.stop()
            self.tray_icon = None  # 明确设置为 None
        # 关闭窗口
        self.root.destroy()

if __name__ == "__main__":
    # 检查是否已经有实例在运行
    if not singleton():
        # 已经有实例在运行,显示提示并退出
        import ctypes
        ctypes.windll.user32.MessageBoxW(0, "多任务倒计时工具已经在运行中!", "提示", 0)
        sys.exit()
    
    root = tk.Tk()
    app = CountdownApp(root)
    root.mainloop()




## 最后
如果觉得好用,请给个回复支持一下,谢谢!如果有任何问题或建议,也欢迎在本帖中提出,我会尽量解答。



蓝奏云最新下载: https://wwbbs.lanzouq.com/iJqrl3k6d73i 密码:52pj 解压密码 52pj

免费评分

参与人数 8吾爱币 +14 热心值 +7 收起 理由
rs20401 + 1 + 1 超级好的工具 如果提醒方式可以加入仅有声音 可以置顶界面就好了
kingtod + 1 + 1 谢谢@Thanks!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
timeni + 1 + 1 谢谢@Thanks!
zhengsuijian + 1 + 1 谢谢@Thanks!
linglong2013 + 1 谢谢,这个真不错&amp;amp;#128077;
naixubao + 1 + 1 谢谢@Thanks!
SAHAQUIEL + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

地球守护者 发表于 2026-3-5 12:12
楼层主人,100MB大小,使用蓝奏·云存储,非常可以,百度网盘。。。
 楼主| fboy19871218 发表于 2026-3-9 10:23
本帖最后由 fboy19871218 于 2026-3-9 10:26 编辑

修复隐藏托盘后,计时有延迟的BUG
重新提交源码:
[Python] 纯文本查看 复制代码
import tkinter as tk
from tkinter import ttk, messagebox
import time
import threading
import pystray
from PIL import Image, ImageDraw
import os
import sys
import tempfile
import json

# 取消单例模式,允许多实例运行
def singleton():
    """允许多实例运行"""
    return True

# 自定义消息框函数,确保在屏幕居中显示
def show_center_messagebox(title, message, icon='warning'):
    """显示居中的消息框"""
    # 创建自定义消息框窗口
    msg_window = tk.Toplevel()
    msg_window.title(title)
    msg_window.resizable(False, False)
    msg_window.transient()  # 设置为临时窗口
    msg_window.grab_set()  # 模态窗口
    
    # 固定窗口大小,确保完整显示所有内容
    window_width = 400
    window_height = 180
    
    # 计算屏幕中心位置
    screen_width = msg_window.winfo_screenwidth()
    screen_height = msg_window.winfo_screenheight()
    x = (screen_width - window_width) // 2
    y = (screen_height - window_height) // 2
    msg_window.geometry(f"{window_width}x{window_height}+{x}+{y}")
    
    # 设置窗口样式
    msg_window.configure(bg="#ffffff")
    
    # 消息文本
    message_label = ttk.Label(msg_window, text=message, wraplength=window_width-40, justify=tk.CENTER, font= ("Microsoft YaHei", 11))
    message_label.pack(pady=(20, 20), padx=20, fill=tk.BOTH, expand=True)
    
    # 确定按钮
    def on_ok():
        msg_window.destroy()
    
    # 创建按钮
    ok_button = ttk.Button(msg_window, text="确定", command=on_ok, width=10)
    ok_button.pack(pady=(0, 20))
    
    # 等待窗口关闭
    msg_window.wait_window()

class CountdownApp:
    def __init__(self, root):
        self.root = root
        # 先隐藏窗口,避免启动时闪烁
        self.root.withdraw()
        
        self.root.title("多任务倒计时工具")
        # 设置窗口图标
        import os
        import sys
        # 获取当前脚本所在目录
        if getattr(sys, 'frozen', False):
            # 打包后的环境
            if hasattr(sys, '_MEIPASS'):
                # 使用 PyInstaller 的临时目录
                script_dir = sys._MEIPASS
            else:
                # 回退到可执行文件目录
                script_dir = os.path.dirname(sys.executable)
        else:
            # 开发环境
            script_dir = os.path.dirname(os.path.abspath(__file__))
        icon_path = os.path.join(script_dir, 'favicon.ico')
        try:
            if os.path.exists(icon_path):
                self.root.iconbitmap(icon_path)
        except:
            pass  # 如果图标文件不存在或设置失败,忽略错误
        # 基础窗口尺寸
        self.root.geometry("920x550")
        # 设置窗口居中
        self.center_window(920, 550)
        
        # 完成所有设置后显示窗口
        self.root.deiconify()
        
        # 固定窗口大小,不可调整
        self.root.resizable(False, False)
        self.root.configure(bg="#ffffff")

        # ===== 自定义样式 =====
        self.style = ttk.Style(self.root)
        # 设置主题(基础主题)
        self.style.theme_use("clam")
        # 自定义字体 - 统一白底黑字加粗
        self.style.configure(".", font=("Microsoft YaHei", 10, "bold"), foreground="#000000", background="#ffffff")
        # 按钮样式
        self.style.configure("TButton", 
                            font=("Microsoft YaHei", 10, "bold"),
                            background="#22c55e",
                            foreground="white",
                            padding=6)
        self.style.map("TButton",
                       background=[("active", "#16a34a")])
        # 复制按钮样式
        self.style.configure("Copy.TButton", 
                            font=("Microsoft YaHei", 10, "bold"),
                            background="#f59e0b",
                            foreground="white",
                            padding=6)
        self.style.map("Copy.TButton",
                       background=[("active", "#d97706")])
        # 标签样式
        self.style.configure("Title.TLabel", 
                             font=("Microsoft YaHei", 12, "bold"),
                             foreground="#000000",
                             background="#ffffff")
        self.style.configure("Task.TLabel", 
                             font=("Microsoft YaHei", 10, "bold"),
                             foreground="#000000",
                             background="#ffffff")
        self.style.configure("Warning.TLabel",
                             font=("Microsoft YaHei", 10, "bold"),
                             foreground="#dc2626",
                             background="#ffffff")
        # 倒计时任务样式(蓝色背景,加粗字体,蓝色边框)
        self.style.configure("Countdown.TFrame",
                             background="#e6f0ff",
                             bordercolor="#3b82f6",
                             relief="solid",
                             borderwidth=2)
        self.style.configure("Countdown.TLabel",
                             font=("Microsoft YaHei", 10, "bold"),
                             foreground="#000000",
                             background="#e6f0ff")
        # 定时提醒任务样式(绿色背景,加粗字体,绿色边框)
        self.style.configure("Reminder.TFrame",
                             background="#dcfce7",
                             bordercolor="#22c55e",
                             relief="solid",
                             borderwidth=2)
        self.style.configure("Reminder.TLabel",
                             font=("Microsoft YaHei", 10, "bold"),
                             foreground="#000000",
                             background="#dcfce7")
        # 列表框架样式
        self.style.configure("List.TFrame",
                             background="#ffffff")
        # 标签框架样式
        self.style.configure("Title.TFrame",
                             background="#ffffff",
                             bordercolor="#000000",
                             relief="ridge",
                             borderwidth=6)
        # 输入框样式
        self.style.configure("TEntry",
                             fieldbackground="#ffffff",
                             foreground="#000000",
                             bordercolor="#000000",
                             relief="ridge",
                             borderwidth=2)
        # 下拉框样式
        self.style.configure("TCombobox",
                             fieldbackground="#ffffff",
                             foreground="#000000",
                             bordercolor="#000000",
                             relief="ridge",
                             borderwidth=2)
        
        # 存储倒计时任务
        self.countdown_tasks = []
        # 存储提醒任务
        self.reminder_tasks = []
        # 存储当前显示的提醒窗口
        self.alert_windows = []
        # 托盘图标
        self.tray_icon = None
        # 任务更新线程控制
        self.running = True
        # 绑定窗口最小化事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)
        # 绑定窗口最小化事件
        self.root.bind("<Unmap>", self.on_minimize)
        # 延迟初始化托盘图标
        self.root.after(100, self.init_tray_icon)
        # 启动任务更新线程
        import threading
        self.update_thread = threading.Thread(target=self.update_tasks, daemon=True)
        self.update_thread.start()

        # ===== 界面布局 =====
        # 1. 标题区域
        title_frame = ttk.Frame(root, style="Title.TFrame")
        title_frame.pack(fill=tk.X, padx=20, pady=0)
        title_label = ttk.Label(title_frame, text="多任务倒计时工具", style="Title.TLabel")
        title_label.pack(anchor=tk.CENTER, pady=20)

        # 2. 输入区域(带边框)
        input_frame = ttk.LabelFrame(root, text="倒计提醒", padding="10", style="Title.TFrame")
        input_frame.pack(fill=tk.X, padx=20, pady=0)

        # 输入网格布局
        ttk.Label(input_frame, text="任务名称:", style="Task.TLabel").grid(row=0, column=0, padx=5, pady=4, sticky=tk.E)
        self.name_entry = ttk.Entry(input_frame, width=15)
        self.name_entry.grid(row=0, column=1, padx=5, pady=4)
        self.name_entry.insert(0, "我的倒计提醒")  # 默认名称
        self.name_entry.config(font= ("Microsoft YaHei", 10))
        # 绑定点击事件,清除默认文本
        self.name_entry.bind("<FocusIn>", self.clear_default_text)
        # 绑定回车键触发添加任务
        self.name_entry.bind("<Return>", lambda e: self.add_countdown())

        # 时间输入组
        time_frame = ttk.Frame(input_frame)
        time_frame.grid(row=0, column=2, padx=10, pady=4, columnspan=1)
        ttk.Label(time_frame, text="时长:", style="Task.TLabel").grid(row=0, column=0, padx=5)
        self.hour_entry = ttk.Entry(time_frame, width=6)
        self.hour_entry.grid(row=0, column=1, padx=2)
        self.hour_entry.insert(0, "0")
        # 绑定回车键触发添加任务
        self.hour_entry.bind("<Return>", lambda e: self.add_countdown())
        ttk.Label(time_frame, text="时", style="Task.TLabel").grid(row=0, column=2, padx=2)

        self.minute_entry = ttk.Entry(time_frame, width=6)
        self.minute_entry.grid(row=0, column=3, padx=2)
        self.minute_entry.insert(0, "0")
        # 绑定回车键触发添加任务
        self.minute_entry.bind("<Return>", lambda e: self.add_countdown())
        ttk.Label(time_frame, text="分", style="Task.TLabel").grid(row=0, column=4, padx=2)

        self.second_entry = ttk.Entry(time_frame, width=6)
        self.second_entry.grid(row=0, column=5, padx=2)
        self.second_entry.insert(0, "10")
        # 绑定回车键触发添加任务
        self.second_entry.bind("<Return>", lambda e: self.add_countdown())
        ttk.Label(time_frame, text="秒                                           ", style="Task.TLabel").grid(row=0, column=6, padx=2)

        # 新增按钮(使用默认TButton样式,确保可见)
        add_btn = ttk.Button(input_frame, text="添加任务", command=self.add_countdown)
        add_btn.grid(row=0, column=3, padx=30, pady=4)

        # 3. 定时提醒区域
        reminder_frame = ttk.LabelFrame(root, text="定时提醒", padding="10", style="Title.TFrame")
        reminder_frame.pack(fill=tk.X, padx=20, pady=0)

        # 定时提醒输入 - 调整布局以适应1050宽度
        ttk.Label(reminder_frame, text="提醒名称:", style="Task.TLabel").grid(row=0, column=0, padx=5, pady=4, sticky=tk.E)
        self.reminder_name_entry = ttk.Entry(reminder_frame, width=15)
        self.reminder_name_entry.grid(row=0, column=1, padx=5, pady=4)
        self.reminder_name_entry.insert(0, "我的定时提醒")  # 默认名称
        self.reminder_name_entry.config(font= ("Microsoft YaHei", 10))
        # 绑定点击事件,清除默认文本
        self.reminder_name_entry.bind("<FocusIn>", self.clear_reminder_default_text)
        # 绑定回车键触发添加提醒
        self.reminder_name_entry.bind("<Return>", lambda e: self.add_reminder())

        # 日期时间选择
        ttk.Label(reminder_frame, text="提醒时间:", style="Task.TLabel").grid(row=0, column=2, padx=5, pady=4, sticky=tk.E)
        
        # 获取当前北京时间,并加上30秒
        import datetime
        now = datetime.datetime.now()
        reminder_time = now + datetime.timedelta(seconds=30)
        
        # 日期时间选择合并为一行
        datetime_frame = ttk.Frame(reminder_frame)
        datetime_frame.grid(row=0, column=2, padx=5, pady=4, columnspan=1, sticky=tk.W)
        
        # 日期部分
        ttk.Label(datetime_frame, text="日期:", style="Task.TLabel").pack(side=tk.LEFT, padx=1)
        self.reminder_year = ttk.Combobox(datetime_frame, width=5, values=[str(reminder_time.year), str(reminder_time.year+1)])
        self.reminder_year.pack(side=tk.LEFT, padx=1)
        self.reminder_year.set(str(reminder_time.year))
        # 绑定回车键触发添加提醒
        self.reminder_year.bind("<Return>", lambda e: self.add_reminder())
        
        ttk.Label(datetime_frame, text="年", style="Task.TLabel").pack(side=tk.LEFT, padx=0)
        self.reminder_month = ttk.Combobox(datetime_frame, width=3, values=[f"{i:02d}" for i in range(1, 13)])
        self.reminder_month.pack(side=tk.LEFT, padx=1)
        self.reminder_month.set(f"{reminder_time.month:02d}")
        # 绑定回车键触发添加提醒
        self.reminder_month.bind("<Return>", lambda e: self.add_reminder())
        
        ttk.Label(datetime_frame, text="月", style="Task.TLabel").pack(side=tk.LEFT, padx=0)
        self.reminder_day = ttk.Combobox(datetime_frame, width=3, values=[f"{i:02d}" for i in range(1, 32)])
        self.reminder_day.pack(side=tk.LEFT, padx=1)
        self.reminder_day.set(f"{reminder_time.day:02d}")
        # 绑定回车键触发添加提醒
        self.reminder_day.bind("<Return>", lambda e: self.add_reminder())
        ttk.Label(datetime_frame, text="日", style="Task.TLabel").pack(side=tk.LEFT, padx=5)
        
        # 时间部分
        ttk.Label(datetime_frame, text="时间:", style="Task.TLabel").pack(side=tk.LEFT, padx=1)
        self.reminder_hour = ttk.Combobox(datetime_frame, width=3, values=[f"{i:02d}" for i in range(24)])
        self.reminder_hour.pack(side=tk.LEFT, padx=1)
        self.reminder_hour.set(f"{reminder_time.hour:02d}")
        # 绑定回车键触发添加提醒
        self.reminder_hour.bind("<Return>", lambda e: self.add_reminder())
        ttk.Label(datetime_frame, text="时", style="Task.TLabel").pack(side=tk.LEFT, padx=0)
        
        self.reminder_minute = ttk.Combobox(datetime_frame, width=3, values=[f"{i:02d}" for i in range(60)])
        self.reminder_minute.pack(side=tk.LEFT, padx=1)
        self.reminder_minute.set(f"{reminder_time.minute:02d}")
        # 绑定回车键触发添加提醒
        self.reminder_minute.bind("<Return>", lambda e: self.add_reminder())
        ttk.Label(datetime_frame, text="分", style="Task.TLabel").pack(side=tk.LEFT, padx=1)
        
        # 新增秒选择
        self.reminder_second = ttk.Combobox(datetime_frame, width=3, values=[f"{i:02d}" for i in range(60)])
        self.reminder_second.pack(side=tk.LEFT, padx=1)
        self.reminder_second.set(f"{reminder_time.second:02d}")
        # 绑定回车键触发添加提醒
        self.reminder_second.bind("<Return>", lambda e: self.add_reminder())
        ttk.Label(datetime_frame, text="秒", style="Task.TLabel").pack(side=tk.LEFT, padx=1)
        
        # 添加提醒按钮 - 与添加任务按钮对齐
        add_reminder_btn = ttk.Button(reminder_frame, text="添加提醒", command=self.add_reminder)
        add_reminder_btn.grid(row=0, column=3, padx=10, pady=4)

        # 4. 主内容区域(左右布局)
        main_content_frame = ttk.Frame(root, style="List.TFrame")
        main_content_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=(0, 10))  # 保持左右内边距
        
        # 固定主内容区域宽度为880px(920-20*2)
        main_content_frame.update_idletasks()
        main_content_frame.config(width=880)
        
        # 当前任务列表,占据整个主内容区域
        left_frame = ttk.LabelFrame(main_content_frame, text="当前任务列表", padding="15", style="Title.TFrame")
        left_frame.place(x=0, y=0, width=880, relheight=1)  # 宽度880,占据整个主内容区域
        

        


        # 任务容器(带滚动条)
        self.task_canvas = tk.Canvas(left_frame, bg="#ffffff", highlightthickness=0)
        scrollbar = ttk.Scrollbar(left_frame, orient=tk.VERTICAL, command=self.task_canvas.yview)
        self.scrollable_frame = ttk.Frame(self.task_canvas, style="List.TFrame")

        # 创建窗口并保存引用
        scrollable_window = self.task_canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        
        # 绑定scrollable_frame的配置事件
        def on_frame_configure(event):
            try:
                if not self.task_canvas.winfo_exists():
                    return
                self.task_canvas.configure(scrollregion=self.task_canvas.bbox("all"))
                # 检查是否需要显示滚动条
                if self.task_canvas.winfo_height() > 0:  # 确保canvas已经初始化
                    if self.task_canvas.bbox("all")[3] > self.task_canvas.winfo_height():
                        if not scrollbar.winfo_ismapped():
                            scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
                            # 调整scrollable_window的宽度
                            self.task_canvas.itemconfig(scrollable_window, width=self.task_canvas.winfo_width() - scrollbar.winfo_width())
                    else:
                        if scrollbar.winfo_ismapped():
                            scrollbar.pack_forget()
                            # 调整scrollable_window的宽度
                            self.task_canvas.itemconfig(scrollable_window, width=self.task_canvas.winfo_width())
            except Exception as e:
                print(f"配置框架失败: {e}")
        
        self.scrollable_frame.bind("<Configure>", on_frame_configure)
        
        # 绑定canvas的配置事件,让scrollable_frame宽度随canvas调整
        def on_canvas_configure(event):
            try:
                if not self.task_canvas.winfo_exists():
                    return
                # 确保scrollable_frame宽度与canvas一致,减去滚动条的宽度
                if scrollbar.winfo_ismapped():
                    scrollbar_width = scrollbar.winfo_width()
                    self.task_canvas.itemconfig(scrollable_window, width=event.width - scrollbar_width)
                else:
                    self.task_canvas.itemconfig(scrollable_window, width=event.width)
            except Exception as e:
                print(f"配置画布失败: {e}")
        
        self.task_canvas.bind("<Configure>", on_canvas_configure)
        
        self.task_canvas.configure(yscrollcommand=scrollbar.set)

        self.task_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        # 加载任务存档
        self.load_tasks()
        

        

        




    def center_window(self, width, height):
        """将窗口居中显示"""
        # 获取屏幕尺寸
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        # 计算居中坐标
        x = (screen_width - width) // 2
        y = (screen_height - height) // 2
        # 设置窗口位置
        self.root.geometry(f"{width}x{height}+{x}+{y}")

    def clear_default_text(self, event):
        """点击任务名称输入框时清除默认文本"""
        if self.name_entry.get() == "我的倒计提醒":
            self.name_entry.delete(0, tk.END)
    
    def clear_reminder_default_text(self, event):
        """点击提醒名称输入框时清除默认文本"""
        if self.reminder_name_entry.get() == "我的定时提醒":
            self.reminder_name_entry.delete(0, tk.END)

    def add_countdown(self):
        """新增倒计时任务"""
        # 检查任务数量限制
        total_tasks = len(self.countdown_tasks) + len(self.reminder_tasks)
        if total_tasks >= 10:
            show_center_messagebox("任务数量限制", "当前任务列表最多只能添加10条任务,请先删除部分任务后再添加!")
            return
            
        # 1. 输入验证
        name = self.name_entry.get().strip()
        if not name:
            show_center_messagebox("输入提示", "任务名称不能为空!")
            return

        try:
            hour = int(self.hour_entry.get())
            minute = int(self.minute_entry.get())
            second = int(self.second_entry.get())
            total_seconds = hour * 3600 + minute * 60 + second
            if total_seconds <= 0:
                show_center_messagebox("输入提示", "总时长必须大于0秒!")
                return
        except ValueError:
            show_center_messagebox("输入提示", "时/分/秒必须输入有效数字!")
            return

        # 2. 创建任务行(带边框)
        task_row = ttk.Frame(self.scrollable_frame, style="Countdown.TFrame")
        task_row.pack(fill=tk.X, pady=0, ipady=8, padx=0)

        # 创建内部框架来控制布局
        inner_frame = ttk.Frame(task_row, style="Countdown.TFrame")
        inner_frame.pack(fill=tk.X, expand=True, padx=5)
        
        # 配置三列布局,使用固定宽度
        inner_frame.columnconfigure(0, minsize=400)  # 任务名称固定宽度
        inner_frame.columnconfigure(1, minsize=150)  # 时间固定宽度
        inner_frame.columnconfigure(2, minsize=200)  # 按钮区固定宽度
        inner_frame.rowconfigure(0, weight=1)  # 行占满高度

        # 任务名称 - 添加[倒计提醒]前缀
        name_label = ttk.Label(inner_frame, text=f"[倒计提醒] {name}", style="Countdown.TLabel", anchor=tk.W, width=30)
        name_label.grid(row=0, column=0, sticky="w", padx=5)

        # 剩余时间 - 与表头对齐(居中)
        remaining_label = ttk.Label(inner_frame, text=self.format_time(total_seconds), style="Countdown.TLabel", anchor=tk.CENTER, width=10)
        remaining_label.grid(row=0, column=1, sticky="we", padx=5)

        # 3. 存储任务信息
        import datetime
        import time
        target_time = datetime.datetime.now() + datetime.timedelta(seconds=total_seconds)
        start_time = time.time()  # 记录任务开始时间
        task_info = {
            "name": name,
            "total_seconds": total_seconds,
            "remaining_seconds": total_seconds,
            "target_time": target_time,
            "start_time": start_time,
            "thread": None,
            "label": remaining_label,
            "row": task_row,
            "running": True
        }
        self.countdown_tasks.append(task_info)

        # 按钮区框架
        button_frame = ttk.Frame(inner_frame, style="Countdown.TFrame")
        button_frame.grid(row=0, column=2, sticky="we", padx=5)
        
        # 删除按钮
        delete_btn = ttk.Button(button_frame, text="删除", command=lambda r=task_row, info=task_info: self.delete_countdown(r, info), width=10)
        delete_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
        
        # 复制按钮
        copy_btn = ttk.Button(button_frame, text="复制", command=lambda info=task_info: self.copy_task(info), width=10, style="Copy.TButton")
        copy_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)

        # 任务将由 update_tasks 方法统一处理

        # 清空输入框(恢复默认名称)
        self.name_entry.delete(0, tk.END)
        self.name_entry.insert(0, "我的倒计提醒")
        self.hour_entry.delete(0, tk.END)
        self.hour_entry.insert(0, "0")
        self.minute_entry.delete(0, tk.END)
        self.minute_entry.insert(0, "0")
        self.second_entry.delete(0, tk.END)
        self.second_entry.insert(0, "10")

    def update_tasks(self):
        """统一更新所有任务的状态(在独立线程中运行)"""
        import time
        # 收集需要更新的UI操作
        ui_updates = []
        
        while self.running:
            try:
                current_time = time.time()
                ui_updates.clear()
                
                # 处理倒计时任务
                for task_info in self.countdown_tasks:
                    if task_info["running"] and task_info["remaining_seconds"] > 0:
                        # 使用基于系统时间的精确计算
                        if "start_time" in task_info:
                            # 计算已经过去的时间
                            elapsed = current_time - task_info["start_time"]
                            # 重新计算剩余时间
                            task_info["remaining_seconds"] = max(0, task_info["total_seconds"] - elapsed)
                        else:
                            # 初始化开始时间
                            task_info["start_time"] = current_time
                        
                        if task_info["remaining_seconds"] <= 0:
                            task_info["remaining_seconds"] = 0
                            # 任务完成,显示提醒
                            # 在主线程中显示提醒
                            self.root.after(0, lambda name=task_info["name"]: self.show_alert(name, task_type="countdown", task_info=task_info))
                    # 无论窗口是否隐藏,都更新时间标签(如果标签存在)
                    if "label" in task_info and task_info["label"] and task_info["running"]:
                        # 检查是否需要更新UI
                        need_update = False
                        if "last_update" in task_info:
                            if current_time - task_info["last_update"] >= 0.1:  # 每0.1秒更新一次UI
                                need_update = True
                                task_info["last_update"] = current_time
                        else:
                            need_update = True
                            task_info["last_update"] = current_time
                        
                        if need_update:
                            # 收集UI更新操作
                            def create_update_func(task_info):
                                def update_func():
                                    try:
                                        if task_info["remaining_seconds"] <= 0:
                                            task_info["label"].config(text="&#9989; 时间到!", foreground="#dc2626")
                                        else:
                                            task_info["label"].config(text=self.format_time(task_info["remaining_seconds"]))
                                    except tk.TclError:
                                        # 标签已被销毁,忽略错误
                                        pass
                                return update_func
                            ui_updates.append(create_update_func(task_info))
                
                # 处理提醒任务
                for reminder_info in self.reminder_tasks:
                    if reminder_info["running"] and reminder_info["remaining_seconds"] > 0:
                        # 使用基于系统时间的精确计算
                        if "target_time" in reminder_info:
                            # 计算剩余时间
                            import datetime
                            current_datetime = datetime.datetime.now()
                            remaining = (reminder_info["target_time"] - current_datetime).total_seconds()
                            reminder_info["remaining_seconds"] = max(0, remaining)
                        
                        if reminder_info["remaining_seconds"] <= 0:
                            reminder_info["remaining_seconds"] = 0
                            # 任务完成,显示提醒
                            # 在主线程中显示提醒
                            self.root.after(0, lambda name=reminder_info["name"]: self.show_alert(name, task_type="reminder", task_info=reminder_info))
                    # 无论窗口是否隐藏,都更新时间标签(如果标签存在)
                    if "label" in reminder_info and reminder_info["label"] and reminder_info["running"]:
                        # 检查是否需要更新UI
                        need_update = False
                        if "last_update" in reminder_info:
                            if current_time - reminder_info["last_update"] >= 0.1:  # 每0.1秒更新一次UI
                                need_update = True
                                reminder_info["last_update"] = current_time
                        else:
                            need_update = True
                            reminder_info["last_update"] = current_time
                        
                        if need_update:
                            # 收集UI更新操作
                            def create_update_func(reminder_info):
                                def update_func():
                                    try:
                                        if reminder_info["remaining_seconds"] <= 0:
                                            reminder_info["label"].config(text="&#9989; 时间到!", foreground="#dc2626")
                                        else:
                                            reminder_info["label"].config(text=self.format_time(reminder_info["remaining_seconds"]))
                                    except tk.TclError:
                                        # 标签已被销毁,忽略错误
                                        pass
                                return update_func
                            ui_updates.append(create_update_func(reminder_info))
                
                # 批量执行UI更新
                if ui_updates:
                    def batch_update():
                        for update_func in ui_updates:
                            update_func()
                    self.root.after(0, batch_update)
            except Exception as e:
                print(f"更新任务失败: {e}")
            finally:
                # 短暂休眠,避免CPU占用过高
                time.sleep(0.1)
    
    def delete_reminder(self, task_row, reminder_info):
        """删除提醒任务"""
        # 停止任务线程
        reminder_info["running"] = False
        # 销毁任务行
        task_row.destroy()
        # 从任务列表中移除
        if reminder_info in self.reminder_tasks:
            self.reminder_tasks.remove(reminder_info)
        # 更新滚动区域
        self.update_scrollable_frame()
    
    def copy_reminder(self, reminder_info):
        """复制定时提醒任务"""
        # 创建复制对话框
        copy_window = tk.Toplevel(self.root)
        copy_window.title("复制定时提醒")
        copy_window.resizable(False, False)
        copy_window.transient(self.root)
        copy_window.grab_set()
        
        # 设置窗口大小和位置
        window_width = 500
        window_height = 250
        screen_width = copy_window.winfo_screenwidth()
        screen_height = copy_window.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        copy_window.geometry(f"{window_width}x{window_height}+{x}+{y}")
        copy_window.configure(bg="#ffffff")
        
        # 创建内容框架
        content_frame = ttk.Frame(copy_window, padding=20)
        content_frame.pack(fill=tk.BOTH, expand=True)
        
        # 配置列权重,使内容居中
        content_frame.columnconfigure(0, weight=1)
        content_frame.columnconfigure(1, weight=0)
        content_frame.columnconfigure(2, weight=1)
        
        # 任务名称输入 - 居中显示
        ttk.Label(content_frame, text="提醒名称:", style="Task.TLabel").grid(row=0, column=0, padx=5, pady=10, sticky=tk.E)
        name_var = tk.StringVar(value=reminder_info["name"])
        name_entry = ttk.Entry(content_frame, textvariable=name_var, width=20)
        name_entry.grid(row=0, column=1, padx=5, pady=10, sticky=tk.W)
        ttk.Label(content_frame, text="", style="Task.TLabel").grid(row=0, column=2, padx=5, pady=10)
        
        # 时间选择 - 居中显示
        ttk.Label(content_frame, text="提醒时间:", style="Task.TLabel").grid(row=1, column=0, padx=5, pady=10, sticky=tk.E)
        
        # 时间选择框架
        time_frame = ttk.Frame(content_frame)
        time_frame.grid(row=1, column=1, padx=5, pady=10, sticky=tk.W)
        
        # 获取当前时间
        import datetime
        if "target_time" in reminder_info:
            target_time = reminder_info["target_time"]
        else:
            target_time = datetime.datetime.now() + datetime.timedelta(seconds=30)
        
        # 时间部分(只显示时分秒)
        hour_var = tk.StringVar(value=f"{target_time.hour:02d}")
        hour_entry = ttk.Combobox(time_frame, textvariable=hour_var, width=3, values=[f"{i:02d}" for i in range(24)])
        hour_entry.pack(side=tk.LEFT, padx=1)
        ttk.Label(time_frame, text="时", style="Task.TLabel").pack(side=tk.LEFT, padx=0)
        
        minute_var = tk.StringVar(value=f"{target_time.minute:02d}")
        minute_entry = ttk.Combobox(time_frame, textvariable=minute_var, width=3, values=[f"{i:02d}" for i in range(60)])
        minute_entry.pack(side=tk.LEFT, padx=1)
        ttk.Label(time_frame, text="分", style="Task.TLabel").pack(side=tk.LEFT, padx=1)
        
        second_var = tk.StringVar(value=f"{target_time.second:02d}")
        second_entry = ttk.Combobox(time_frame, textvariable=second_var, width=3, values=[f"{i:02d}" for i in range(60)])
        second_entry.pack(side=tk.LEFT, padx=1)
        ttk.Label(time_frame, text="秒", style="Task.TLabel").pack(side=tk.LEFT, padx=1)
        
        # 绑定回车键触发确定按钮功能
        name_entry.bind("<Return>", lambda e: on_ok())
        hour_entry.bind("<Return>", lambda e: on_ok())
        minute_entry.bind("<Return>", lambda e: on_ok())
        second_entry.bind("<Return>", lambda e: on_ok())
        
        ttk.Label(content_frame, text="", style="Task.TLabel").grid(row=1, column=2, padx=5, pady=10)
        
        # 按钮框架 - 居中显示
        button_frame = ttk.Frame(content_frame)
        button_frame.grid(row=2, column=0, columnspan=3, pady=20)
        
        # 确定按钮
        def on_ok():
            # 检查任务数量限制
            total_tasks = len(self.countdown_tasks) + len(self.reminder_tasks)
            if total_tasks >= 10:
                show_center_messagebox("任务数量限制", "当前任务列表最多只能添加10条任务,请先删除部分任务后再添加!")
                copy_window.destroy()
                return
            
            # 验证输入
            task_name = name_var.get().strip()
            if not task_name:
                show_center_messagebox("输入提示", "提醒名称不能为空!")
                return
            
            try:
                # 获取当前日期
                current_date = datetime.datetime.now()
                year = current_date.year
                month = current_date.month
                day = current_date.day
                
                # 获取选择的时间
                hour = int(hour_var.get())
                minute = int(minute_var.get())
                second = int(second_var.get())
                
                # 计算目标时间
                target_time = datetime.datetime(year, month, day, hour, minute, second)
                current_time = datetime.datetime.now()
                
                # 计算时间差(秒)
                time_diff = (target_time - current_time).total_seconds()
                
                if time_diff <= 0:
                    show_center_messagebox("输入提示", "提醒时间必须在当前时间之后!")
                    return
                    
            except ValueError:
                show_center_messagebox("输入提示", "请输入有效的日期时间!")
                return
            
            # 创建新的定时提醒任务
            # 2. 创建任务行
            task_row = ttk.Frame(self.scrollable_frame, style="Reminder.TFrame")
            task_row.pack(fill=tk.X, pady=0, ipady=8, padx=0)
            
            # 创建内部框架来控制布局
            inner_frame = ttk.Frame(task_row, style="Reminder.TFrame")
            inner_frame.pack(fill=tk.X, expand=True, padx=5)
            
            # 配置三列布局,使用固定宽度
            inner_frame.columnconfigure(0, minsize=400)  # 任务名称固定宽度
            inner_frame.columnconfigure(1, minsize=150)  # 时间固定宽度
            inner_frame.columnconfigure(2, minsize=200)  # 按钮区固定宽度
            inner_frame.rowconfigure(0, weight=1)  # 行占满高度
            
            # 任务名称(标记为提醒) - 与表头对齐,使用ellipsis处理长文本
            name_label = ttk.Label(inner_frame, text=f"[定时提醒] {task_name}", style="Reminder.TLabel", anchor=tk.W, width=30, )
            name_label.grid(row=0, column=0, sticky="w", padx=5)
            
            # 剩余时间 - 与表头对齐(居中)
            remaining_label = ttk.Label(inner_frame, text=self.format_time(int(time_diff)), style="Reminder.TLabel", anchor=tk.CENTER, width=10)
            remaining_label.grid(row=0, column=1, sticky="we", padx=5)
            
            # 3. 存储任务信息
            new_reminder_info = {
                "name": task_name,
                "target_time": target_time,
                "remaining_seconds": int(time_diff),
                "thread": None,
                "label": remaining_label,
                "row": task_row,
                "running": True
            }
            self.reminder_tasks.append(new_reminder_info)
            
            # 按钮区框架
            button_frame = ttk.Frame(inner_frame, style="Reminder.TFrame")
            button_frame.grid(row=0, column=2, sticky="we", padx=5)
            
            # 删除按钮
            delete_btn = ttk.Button(button_frame, text="删除", command=lambda r=task_row, info=new_reminder_info: self.delete_reminder(r, info), width=10)
            delete_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
            
            # 复制按钮
            copy_btn = ttk.Button(button_frame, text="复制", command=lambda info=new_reminder_info: self.copy_reminder(info), width=10, style="Copy.TButton")
            copy_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
            
            # 任务将由 update_tasks 方法统一处理
            
            # 关闭对话框
            copy_window.destroy()
        
        # 取消按钮
        def on_cancel():
            copy_window.destroy()
        
        # 按钮
        ok_button = ttk.Button(button_frame, text="确定", command=on_ok, width=10)
        ok_button.pack(side=tk.LEFT, padx=10)
        cancel_button = ttk.Button(button_frame, text="取消", command=on_cancel, width=10)
        cancel_button.pack(side=tk.LEFT, padx=10)

    def update_time_label(self, task_info, finished=False):
        """更新剩余时间显示"""
        # 检查任务是否仍在运行,避免更新已删除任务的标签
        if not task_info.get("running"):
            return
        
        try:
            # 根据任务类型选择正确的样式
            task_type = "Countdown"
            if "target_time" in task_info:
                task_type = "Reminder"
            
            if finished:
                # 保持标签的背景色与任务类型一致
                task_info["label"].config(text="&#9989; 时间到!", foreground="#dc2626")
            else:
                task_info["label"].config(text=self.format_time(task_info["remaining_seconds"]), style=f"{task_type}.TLabel")
        except tk.TclError:
            # 标签已被销毁,忽略错误
            pass

    def format_time(self, seconds):
        """格式化时间为 00:00:00"""
        # 将浮点数转换为整数
        seconds = int(seconds)
        h = seconds // 3600
        m = (seconds % 3600) // 60
        s = seconds % 60
        return f"{h:02d}:{m:02d}:{s:02d}"

    def delete_countdown(self, task_row, task_info):
        """删除倒计时任务"""
        # 停止任务线程
        task_info["running"] = False
        # 销毁任务行
        task_row.destroy()
        # 从任务列表中移除
        if task_info in self.countdown_tasks:
            self.countdown_tasks.remove(task_info)
        # 更新滚动区域
        self.update_scrollable_frame()
    
    def copy_task(self, task_info):
        """复制任务"""
        # 创建复制对话框
        copy_window = tk.Toplevel(self.root)
        copy_window.title("复制任务")
        copy_window.resizable(False, False)
        copy_window.transient(self.root)
        copy_window.grab_set()
        
        # 设置窗口大小和位置
        window_width = 400
        window_height = 200
        screen_width = copy_window.winfo_screenwidth()
        screen_height = copy_window.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        copy_window.geometry(f"{window_width}x{window_height}+{x}+{y}")
        copy_window.configure(bg="#ffffff")
        
        # 创建内容框架
        content_frame = ttk.Frame(copy_window, padding=20)
        content_frame.pack(fill=tk.BOTH, expand=True)
        
        # 配置列权重,使内容居中
        content_frame.columnconfigure(0, weight=1)
        content_frame.columnconfigure(1, weight=0)
        content_frame.columnconfigure(2, weight=1)
        
        # 任务名称输入 - 居中显示
        ttk.Label(content_frame, text="任务名称:", style="Task.TLabel").grid(row=0, column=0, padx=5, pady=10, sticky=tk.E)
        name_var = tk.StringVar(value=task_info["name"])
        name_entry = ttk.Entry(content_frame, textvariable=name_var, width=20)
        name_entry.grid(row=0, column=1, padx=5, pady=10, sticky=tk.W)
        ttk.Label(content_frame, text="", style="Task.TLabel").grid(row=0, column=2, padx=5, pady=10)
        
        # 倒计时时长输入 - 居中显示
        ttk.Label(content_frame, text="倒计时时长:", style="Task.TLabel").grid(row=1, column=0, padx=5, pady=10, sticky=tk.E)
        
        # 时长输入框架
        time_frame = ttk.Frame(content_frame)
        time_frame.grid(row=1, column=1, padx=5, pady=10, sticky=tk.W)
        
        # 获取当前时长
        duration = task_info["total_seconds"]
        hours = duration // 3600
        minutes = (duration % 3600) // 60
        seconds = duration % 60
        
        # 小时输入
        hour_var = tk.StringVar(value=str(hours))
        hour_entry = ttk.Entry(time_frame, textvariable=hour_var, width=6)
        hour_entry.pack(side=tk.LEFT, padx=2)
        ttk.Label(time_frame, text="时", style="Task.TLabel").pack(side=tk.LEFT, padx=2)
        
        # 分钟输入
        minute_var = tk.StringVar(value=str(minutes))
        minute_entry = ttk.Entry(time_frame, textvariable=minute_var, width=6)
        minute_entry.pack(side=tk.LEFT, padx=2)
        ttk.Label(time_frame, text="分", style="Task.TLabel").pack(side=tk.LEFT, padx=2)
        
        # 秒输入
        second_var = tk.StringVar(value=str(seconds))
        second_entry = ttk.Entry(time_frame, textvariable=second_var, width=6)
        second_entry.pack(side=tk.LEFT, padx=2)
        ttk.Label(time_frame, text="秒", style="Task.TLabel").pack(side=tk.LEFT, padx=2)
        
        # 绑定回车键触发确定按钮功能
        name_entry.bind("<Return>", lambda e: on_ok())
        hour_entry.bind("<Return>", lambda e: on_ok())
        minute_entry.bind("<Return>", lambda e: on_ok())
        second_entry.bind("<Return>", lambda e: on_ok())
        
        ttk.Label(content_frame, text="", style="Task.TLabel").grid(row=1, column=2, padx=5, pady=10)
        
        # 按钮框架 - 居中显示
        button_frame = ttk.Frame(content_frame)
        button_frame.grid(row=2, column=0, columnspan=3, pady=20)
        
        # 确定按钮
        def on_ok():
            # 检查任务数量限制
            total_tasks = len(self.countdown_tasks) + len(self.reminder_tasks)
            if total_tasks >= 10:
                show_center_messagebox("任务数量限制", "当前任务列表最多只能添加10条任务,请先删除部分任务后再添加!")
                copy_window.destroy()
                return
            
            # 验证输入
            task_name = name_var.get().strip()
            if not task_name:
                show_center_messagebox("输入提示", "任务名称不能为空!")
                return
            
            try:
                hours = int(hour_var.get())
                minutes = int(minute_var.get())
                seconds = int(second_var.get())
                total_seconds = hours * 3600 + minutes * 60 + seconds
                if total_seconds <= 0:
                    show_center_messagebox("输入提示", "总时长必须大于0秒!")
                    return
            except ValueError:
                show_center_messagebox("输入提示", "时/分/秒必须输入有效数字!")
                return
            
            # 创建新的倒计时任务
            # 2. 创建任务行(带边框)
            task_row = ttk.Frame(self.scrollable_frame, style="Countdown.TFrame")
            task_row.pack(fill=tk.X, pady=0, ipady=8, padx=0)

            # 创建内部框架来控制布局
            inner_frame = ttk.Frame(task_row, style="Countdown.TFrame")
            inner_frame.pack(fill=tk.X, expand=True, padx=5)
            
            # 配置三列布局,使用固定宽度
            inner_frame.columnconfigure(0, minsize=400)  # 任务名称固定宽度
            inner_frame.columnconfigure(1, minsize=150)  # 时间固定宽度
            inner_frame.columnconfigure(2, minsize=200)  # 按钮区固定宽度
            inner_frame.rowconfigure(0, weight=1)  # 行占满高度

            # 任务名称 - 添加[倒计提醒]前缀,使用ellipsis处理长文本
            name_label = ttk.Label(inner_frame, text=f"[倒计提醒] {task_name}", style="Countdown.TLabel", anchor=tk.W, width=30, )
            name_label.grid(row=0, column=0, sticky="w", padx=5)

            # 剩余时间 - 与表头对齐(居中)
            remaining_label = ttk.Label(inner_frame, text=self.format_time(total_seconds), style="Countdown.TLabel", anchor=tk.CENTER, width=10)
            remaining_label.grid(row=0, column=1, sticky="we", padx=5)

            # 存储任务信息
            import datetime
            import time
            target_time = datetime.datetime.now() + datetime.timedelta(seconds=total_seconds)
            start_time = time.time()  # 记录任务开始时间
            new_task_info = {
                "name": task_name,
                "total_seconds": total_seconds,
                "remaining_seconds": total_seconds,
                "target_time": target_time,
                "start_time": start_time,
                "thread": None,
                "label": remaining_label,
                "row": task_row,
                "running": True
            }
            self.countdown_tasks.append(new_task_info)

            # 按钮区框架
            button_frame = ttk.Frame(inner_frame, style="Countdown.TFrame")
            button_frame.grid(row=0, column=2, sticky="we", padx=5)
            
            # 删除按钮
            delete_btn = ttk.Button(button_frame, text="删除", command=lambda r=task_row, info=new_task_info: self.delete_countdown(r, info), width=10)
            delete_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
            
            # 复制按钮
            copy_btn = ttk.Button(button_frame, text="复制", command=lambda info=new_task_info: self.copy_task(info), width=10, style="Copy.TButton")
            copy_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)

            # 任务将由 update_tasks 方法统一处理
            
            # 关闭对话框
            copy_window.destroy()
        
        # 取消按钮
        def on_cancel():
            copy_window.destroy()
        
        # 按钮
        ok_button = ttk.Button(button_frame, text="确定", command=on_ok, width=10)
        ok_button.pack(side=tk.LEFT, padx=10)
        cancel_button = ttk.Button(button_frame, text="取消", command=on_cancel, width=10)
        cancel_button.pack(side=tk.LEFT, padx=10)
    
    def copy_task_from_alert(self, task_info, task_type):
        """从提醒窗口复制任务"""
        if task_type == "countdown":
            # 复制倒计时任务
            self.copy_task(task_info)
        else:
            # 复制提醒任务
            self.copy_reminder(task_info)
    
    def add_reminder(self):
        """添加定时提醒任务"""
        # 检查任务数量限制
        total_tasks = len(self.countdown_tasks) + len(self.reminder_tasks)
        if total_tasks >= 10:
            show_center_messagebox("任务数量限制", "当前任务列表最多只能添加10条任务,请先删除部分任务后再添加!")
            return
        
        # 1. 输入验证
        name = self.reminder_name_entry.get().strip()
        if not name:
            show_center_messagebox("输入提示", "提醒名称不能为空!")
            return
        
        try:
            # 获取选择的日期时间
            year = int(self.reminder_year.get())
            month = int(self.reminder_month.get())
            day = int(self.reminder_day.get())
            hour = int(self.reminder_hour.get())
            minute = int(self.reminder_minute.get())
            second = int(self.reminder_second.get())
            
            # 计算目标时间
            import datetime
            target_time = datetime.datetime(year, month, day, hour, minute, second)
            current_time = datetime.datetime.now()
            
            # 计算时间差(秒)
            time_diff = (target_time - current_time).total_seconds()
            
            if time_diff <= 0:
                show_center_messagebox("输入提示", "提醒时间必须在当前时间之后!")
                return
                
        except ValueError:
            show_center_messagebox("输入提示", "请输入有效的日期时间!")
            return
        
        # 2. 创建任务行
        task_row = ttk.Frame(self.scrollable_frame, style="Reminder.TFrame")
        task_row.pack(fill=tk.X, pady=0, ipady=8, padx=0)
        
        # 创建内部框架来控制布局
        inner_frame = ttk.Frame(task_row, style="Reminder.TFrame")
        inner_frame.pack(fill=tk.X, expand=True, padx=5)
        
        # 配置三列布局,使用固定宽度
        inner_frame.columnconfigure(0, minsize=400)  # 任务名称固定宽度
        inner_frame.columnconfigure(1, minsize=150)  # 时间固定宽度
        inner_frame.columnconfigure(2, minsize=200)  # 按钮区固定宽度
        inner_frame.rowconfigure(0, weight=1)  # 行占满高度
        
        # 任务名称(标记为提醒) - 与表头对齐
        name_label = ttk.Label(inner_frame, text=f"[定时提醒] {name}", style="Reminder.TLabel", anchor=tk.W, width=30)
        name_label.grid(row=0, column=0, sticky="w", padx=5)
        
        # 剩余时间 - 与表头对齐(居中)
        remaining_label = ttk.Label(inner_frame, text=self.format_time(int(time_diff)), style="Reminder.TLabel", anchor=tk.CENTER, width=10)
        remaining_label.grid(row=0, column=1, sticky="we", padx=5)
        
        # 3. 存储任务信息
        reminder_info = {
            "name": name,
            "target_time": target_time,
            "remaining_seconds": int(time_diff),
            "thread": None,
            "label": remaining_label,
            "row": task_row,
            "running": True
        }
        self.reminder_tasks.append(reminder_info)
        
        # 按钮区框架
        button_frame = ttk.Frame(inner_frame, style="Reminder.TFrame")
        button_frame.grid(row=0, column=2, sticky="we", padx=5)
        
        # 删除按钮
        delete_btn = ttk.Button(button_frame, text="删除", command=lambda r=task_row, info=reminder_info: self.delete_reminder(r, info), width=10)
        delete_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
        
        # 复制按钮
        copy_btn = ttk.Button(button_frame, text="复制", command=lambda info=reminder_info: self.copy_reminder(info), width=10, style="Copy.TButton")
        copy_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
        
        # 任务将由 update_tasks 方法统一处理
        
        # 清空输入框(恢复默认名称)
        self.reminder_name_entry.delete(0, tk.END)
        self.reminder_name_entry.insert(0, "我的定时提醒")

    def show_alert(self, task_name, task_type="countdown", task_info=None):
        """右下角滑入提醒窗口(优化样式)"""
        # 根据任务类型设置颜色
        if task_type == "reminder":
            bg_color = "#22c55e"  # 绿色,用于定时提醒
            title_text = "&#128276; 定时提醒"
        else:
            bg_color = "#3b82f6"  # 蓝色,用于倒计时
            title_text = "&#9200; 倒计时结束"

        # 创建提醒窗口 - 使用None作为父窗口,使其成为顶级窗口
        alert_win = tk.Toplevel(None)
        alert_win.title("提醒")
        alert_win.overrideredirect(True)
        alert_win.geometry("320x160")
        alert_win.configure(bg=bg_color)
        # 确保提醒窗口总是显示在最前面
        alert_win.attributes('-topmost', True)

        # 提醒内容布局
        content_frame = tk.Frame(alert_win, bg=bg_color)
        content_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 标题
        title_label = tk.Label(content_frame, text=title_text, 
                               font=("Microsoft YaHei", 14, "bold"), 
                               bg=bg_color, fg="white")
        title_label.pack(pady=(5, 10))

        # 任务名称
        task_label = tk.Label(content_frame, text=f"任务:{task_name}", 
                              font=("Microsoft YaHei", 12), 
                              bg=bg_color, fg="white")
        task_label.pack(pady=5)

        # 关闭按钮
        close_btn = ttk.Button(content_frame, text="关闭", 
                               command=lambda: self.close_alert(alert_win, task_info, task_type))
        close_btn.pack(pady=(10, 5))

        # 直接获取屏幕尺寸,不依赖主窗口
        import ctypes
        user32 = ctypes.windll.user32
        screen_width = user32.GetSystemMetrics(0)
        screen_height = user32.GetSystemMetrics(1)
        
        win_width = 320
        win_height = 160
        target_x = screen_width - win_width - 30
        # 计算垂直偏移量,实现层叠效果
        target_y = screen_height - win_height - 30 - (len(self.alert_windows) * 20)
        start_x = screen_width

        # 滑入动画
        def slide_in(current_x):
            if current_x > target_x:
                new_x = current_x - 8
                alert_win.geometry(f"{win_width}x{win_height}+{new_x}+{target_y}")
                alert_win.after(15, slide_in, new_x)
            else:
                alert_win.geometry(f"{win_width}x{win_height}+{target_x}+{target_y}")
                # 动画完成后将提醒窗口置于顶层
                alert_win.lift()
                alert_win.focus_force()
                alert_win.attributes('-topmost', True)  # 置于顶层
                alert_win.update()
                alert_win.attributes('-topmost', False)  # 取消顶层设置,避免一直置顶

        slide_in(start_x)
        
        # 将提醒窗口添加到列表中
        self.alert_windows.append(alert_win)
        


    def close_alert(self, alert_win, task_info=None, task_type=None):
        """关闭提醒窗口"""
        try:
            alert_win.destroy()
            # 从提醒窗口列表中移除
            if alert_win in self.alert_windows:
                self.alert_windows.remove(alert_win)
            
            # 如果有任务信息,提供复制任务的选项
            if task_info and task_type:
                # 延迟显示复制对话框,避免事件处理冲突
                self.root.after(100, lambda: self.copy_task_from_alert(task_info, task_type))
                # 延迟移除任务,确保复制操作完成
                self.root.after(500, lambda: self.remove_completed_task(task_info, task_type))
            
            # 显示主窗口
            self.show_window()
        except Exception as e:
            print(f"关闭提醒窗口失败: {e}")
    
    def update_scrollable_frame(self):
        """更新滚动区域,确保删除任务后没有残留背景色"""
        # 取消之前的更新请求,避免累积
        if hasattr(self, '_scroll_update_id'):
            self.root.after_cancel(self._scroll_update_id)
        # 延迟更新滚动区域,避免频繁更新
        self._scroll_update_id = self.root.after(100, self._do_update_scrollable_frame)

    def _do_update_scrollable_frame(self):
        """实际执行滚动区域更新"""
        try:
            self.scrollable_frame.update_idletasks()
            self.task_canvas.configure(scrollregion=self.task_canvas.bbox("all"))
        except Exception as e:
            print(f"更新滚动区域失败: {e}")

    def init_tray_icon(self):
        """延迟初始化托盘图标"""
        pass  # 托盘图标将在需要时创建

    def create_tray_icon(self):
        """创建托盘图标"""
        try:
            # 尝试使用 favicon.ico 作为托盘图标
            import os
            import sys
            
            # 获取应用程序运行目录
            if getattr(sys, 'frozen', False):
                # 打包后的环境
                if hasattr(sys, '_MEIPASS'):
                    # 使用 PyInstaller 的临时目录
                    script_dir = sys._MEIPASS
                else:
                    # 回退到可执行文件目录
                    script_dir = os.path.dirname(sys.executable)
            else:
                # 开发环境
                script_dir = os.path.dirname(os.path.abspath(__file__))
            
            icon_path = os.path.join(script_dir, 'favicon.ico')
            
            if os.path.exists(icon_path):
                try:
                    # 使用现有图标
                    image = Image.open(icon_path)
                except Exception:
                    # 创建一个简单的图标作为备用
                    image = Image.new('RGB', (64, 64), color='#3b82f6')
                    draw = ImageDraw.Draw(image)
                    draw.text((15, 15), "&#9200;", font=None, fill='white')
            else:
                # 创建一个简单的图标作为备用
                image = Image.new('RGB', (64, 64), color='#3b82f6')
                draw = ImageDraw.Draw(image)
                draw.text((15, 15), "&#9200;", font=None, fill='white')
            
            # 创建托盘菜单
            menu = pystray.Menu(
                pystray.MenuItem("显示窗口", self.show_window),
                pystray.MenuItem("显示悬浮窗", self.create_floating_window),
                pystray.MenuItem("退出", self.exit_app)
            )
            
            # 创建托盘图标
            self.tray_icon = pystray.Icon("countdown_app", image, "多任务倒计时工具", menu)
            
            # 启动托盘图标在单独的线程中
            def run_tray():
                try:
                    # 运行托盘图标
                    self.tray_icon.run()
                except Exception:
                    pass
                finally:
                    # 托盘图标停止后释放资源
                    if self.tray_icon:
                        self.tray_icon = None
            
            # 启动托盘图标线程
            tray_thread = threading.Thread(target=run_tray, daemon=True)
            tray_thread.start()
        except Exception:
            pass

    def on_minimize(self, event):
        """处理窗口最小化事件"""
        # 检查是否是最小化事件
        if event.widget == self.root and event.type == tk.EventType.Unmap:
            # 隐藏窗口
            self.root.withdraw()
            # 创建并显示托盘图标
            if not self.tray_icon:
                # 直接创建托盘图标
                self.create_tray_icon()

    def on_close(self):
        """处理窗口关闭事件,最小化到托盘"""
        # 隐藏窗口
        self.root.withdraw()
        # 创建并显示托盘图标
        if not self.tray_icon:
            # 直接创建托盘图标
            self.create_tray_icon()

    def show_window(self):
        """从托盘恢复窗口"""
        try:
            # 显示窗口
            self.root.deiconify()
            # 激活窗口并置于顶层
            self.root.lift()
            self.root.focus_force()
            self.root.attributes('-topmost', True)  # 置于顶层
            self.root.update()
            self.root.attributes('-topmost', False)  # 取消顶层设置,避免一直置顶
            # 隐藏悬浮窗
            self.hide_floating_window()
            # 停止托盘图标
            if self.tray_icon:
                try:
                    self.tray_icon.stop()
                except Exception as e:
                    print(f"停止托盘图标失败: {e}")
                finally:
                    self.tray_icon = None
        except Exception as e:
            print(f"显示窗口失败: {e}")
    
    def create_floating_window(self):
        """创建独立的悬浮窗窗口,彻底解决闪烁问题"""
        try:
            # 检查悬浮窗是否已存在
            if hasattr(self, 'floating_window') and self.floating_window.winfo_exists():
                # 如果已存在,显示并置于顶层
                self.floating_window.lift()
                self.floating_window.attributes('-topmost', True)
                self.floating_window.update()
                self.floating_window.attributes('-topmost', False)
                return
            
            # 先计算窗口位置
            window_width = 400
            window_height = 500
            screen_width = self.root.winfo_screenwidth()
            screen_height = self.root.winfo_screenheight()
            # 计算右下角位置,留出一些边距
            x = screen_width - window_width - 20
            y = screen_height - window_height - 80  # 留出任务栏高度
            
            # 创建一个Toplevel窗口作为悬浮窗
            # 使用更优化的方式避免闪烁问题
            self.floating_window = tk.Toplevel(self.root)
            # 先设置为隐藏状态
            self.floating_window.withdraw()
            # 设置窗口属性
            self.floating_window.title("任务列表")
            self.floating_window.overrideredirect(True)  # 无边框
            self.floating_window.attributes('-topmost', True)  # 置于顶层
            self.floating_window.attributes('-alpha', 0.95)  # 半透明效果
            
            # 直接在指定位置创建窗口
            self.floating_window.geometry(f"{window_width}x{window_height}+{x}+{y}")
            # 强制更新窗口位置和大小
            self.floating_window.update_idletasks()
            # 显示窗口
            self.floating_window.deiconify()
            
            # 亮色风格设计
            # 设置背景色为亮色
            self.floating_window.configure(bg="#ffffff")
            
            # 创建亮色风格的自定义样式
            floating_style = ttk.Style(self.floating_window)
            floating_style.theme_use("clam")
            
            # 标题标签样式
            floating_style.configure("Finance.Title.TLabel", 
                                  font=("Microsoft YaHei", 12, "bold"),
                                  foreground="#333333",
                                  background="#ffffff")
            
            # 隐藏按钮样式
            floating_style.configure("Finance.TButton", 
                                  font=("Microsoft YaHei", 10, "bold"),
                                  background="#f0f0f0",
                                  foreground="#333333",
                                  padding=6)
            floating_style.map("Finance.TButton",
                             background=[("active", "#e0e0e0")])
            
            # 创建主框架
            main_frame = ttk.Frame(self.floating_window)
            main_frame.pack(fill=tk.BOTH, expand=True, padx=2, pady=2)
            
            # 创建标题栏
            title_frame = ttk.Frame(main_frame)
            title_frame.pack(fill=tk.X, padx=10, pady=10)
            
            # 标题 - 金融风格字体
            title_label = ttk.Label(title_frame, text="多任务倒计时工具", style="Finance.Title.TLabel")
            title_label.pack(side=tk.LEFT, padx=5)
            
            # 隐藏按钮 - 金融风格,使用lambda确保正确调用
            hide_btn = ttk.Button(title_frame, text="隐藏", command=lambda: self.hide_floating_window(), width=8, style="Finance.TButton")
            hide_btn.pack(side=tk.RIGHT, padx=5)
            
            # 创建任务列表框架
            task_frame = ttk.Frame(main_frame)
            task_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10))
            
            # 创建任务列表,使用亮色风格样式
            self.task_listbox = tk.Listbox(
                task_frame, 
                font=("Microsoft YaHei", 12),  # 加大字体,使用微软雅黑
                selectbackground="#3b82f6", 
                selectforeground="white",
                bg="#f8f9fa",  # 亮色背景
                fg="#333333",  # 深色文字
                relief="flat",  # 平坦效果
                bd=0,
                highlightthickness=0,
                activestyle="none"
            )
            
            # 添加亮色风格的滚动条
            # 配置滚动条样式
            floating_style.configure("Finance.Vertical.TScrollbar",
                                  background="#e0e0e0",
                                  troughcolor="#f8f9fa",
                                  arrowcolor="#666666",
                                  bordercolor="#d0d0d0",
                                  relief="flat")
            
            scrollbar = ttk.Scrollbar(task_frame, orient=tk.VERTICAL, command=self.task_listbox.yview, style="Finance.Vertical.TScrollbar")
            scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
            self.task_listbox.config(yscrollcommand=scrollbar.set)
            
            # 调整任务列表的pack方式,确保滚动条正确显示
            self.task_listbox.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
            
            # 存储滚动条引用
            self.scrollbar = scrollbar
            
            # 更新任务列表
            self.update_task_list()
            
            # 显示窗口
            self.floating_window.deiconify()
            
            # 定时更新任务列表
            self.floating_window.after(1000, self.update_task_list)
            
        except Exception as e:
            print(f"创建悬浮窗失败: {e}")
    
    def update_task_list(self):
        """更新任务列表"""
        try:
            if not hasattr(self, 'task_listbox') or not self.task_listbox.winfo_exists():
                return
            
            # 清空列表
            self.task_listbox.delete(0, tk.END)
            
            # 计算任务总数
            total_tasks = len(self.countdown_tasks) + len(self.reminder_tasks)
            
            # 如果没有任务,显示提示信息
            if total_tasks == 0:
                self.task_listbox.insert(tk.END, "&#128203; 暂无任务")
                self.task_listbox.itemconfig(0, {'fg': '#999999'})  # 亮色风格灰色
            else:
                # 添加倒计时任务
                for task_info in self.countdown_tasks:
                    if task_info.get("running", False):
                        remaining = int(task_info.get("remaining_seconds", 0))
                        task_name = task_info.get("name", "未知任务")
                        status = f"&#9200; [倒计提醒] {task_name}"
                        time_str = f"剩余: {self.format_time(remaining)}"
                        # 使用任务对象中存储的target_time
                        target_time = task_info.get("target_time")
                        if target_time:
                            # 只显示时间部分,不显示日期
                            target_str = f"目标时间: {target_time.strftime('%H:%M:%S')}"
                        else:
                            # 如果没有target_time,使用当前时间 + 剩余秒数作为备用
                            import datetime
                            target_time = datetime.datetime.now() + datetime.timedelta(seconds=remaining)
                            target_str = f"目标时间: {target_time.strftime('%H:%M:%S')}"
                        self.task_listbox.insert(tk.END, status)
                        self.task_listbox.insert(tk.END, time_str)
                        self.task_listbox.insert(tk.END, target_str)
                        # 设置颜色 - 亮色风格
                        last_idx = self.task_listbox.size() - 1
                        self.task_listbox.itemconfig(last_idx - 2, {'fg': '#3b82f6'})  # 蓝色
                        self.task_listbox.itemconfig(last_idx - 1, {'fg': '#666666'})  # 灰色
                        self.task_listbox.itemconfig(last_idx, {'fg': '#999999'})  # 浅灰色
                        # 添加空行作为分隔
                        self.task_listbox.insert(tk.END, "")
                
                # 添加提醒任务
                for reminder_info in self.reminder_tasks:
                    if reminder_info.get("running", False):
                        remaining = int(reminder_info.get("remaining_seconds", 0))
                        task_name = reminder_info.get("name", "未知任务")
                        status = f"&#128276; [定时提醒] {task_name}"
                        time_str = f"剩余: {self.format_time(remaining)}"
                        # 获取目标时间
                        import datetime
                        target_time = reminder_info.get("target_time", datetime.datetime.now())
                        # 只显示时间部分,不显示日期
                        target_str = f"目标时间: {target_time.strftime('%H:%M:%S')}"
                        self.task_listbox.insert(tk.END, status)
                        self.task_listbox.insert(tk.END, time_str)
                        self.task_listbox.insert(tk.END, target_str)
                        # 设置颜色 - 亮色风格
                        last_idx = self.task_listbox.size() - 1
                        self.task_listbox.itemconfig(last_idx - 2, {'fg': '#22c55e'})  # 绿色
                        self.task_listbox.itemconfig(last_idx - 1, {'fg': '#666666'})  # 灰色
                        self.task_listbox.itemconfig(last_idx, {'fg': '#999999'})  # 浅灰色
                        # 添加空行作为分隔
                        self.task_listbox.insert(tk.END, "")
            
            # 自动显示/隐藏滚动条
            if hasattr(self, 'scrollbar'):
                try:
                    # 检查任务列表是否需要滚动
                    self.task_listbox.update_idletasks()
                    if self.task_listbox.winfo_exists():
                        # 获取任务列表的高度和内容高度
                        listbox_height = self.task_listbox.winfo_height()
                        content_height = self.task_listbox.bbox(tk.END)[3] if self.task_listbox.size() > 0 else 0
                        
                        # 如果内容高度大于列表框高度,显示滚动条
                        if content_height > listbox_height:
                            if not self.scrollbar.winfo_ismapped():
                                self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
                        else:
                            # 否则隐藏滚动条
                            if self.scrollbar.winfo_ismapped():
                                self.scrollbar.pack_forget()
                except Exception as e:
                    print(f"调整滚动条失败: {e}")
            
            # 再次定时更新
            if hasattr(self, 'floating_window') and self.floating_window.winfo_exists():
                self.floating_window.after(1000, self.update_task_list)
        except Exception as e:
            print(f"更新任务列表失败: {e}")
    
    def hide_floating_window(self):
        """隐藏悬浮窗"""
        try:
            if hasattr(self, 'floating_window') and self.floating_window.winfo_exists():
                self.floating_window.destroy()
                delattr(self, 'floating_window')
        except Exception as e:
            print(f"隐藏悬浮窗失败: {e}")





    def remove_completed_task(self, task_info, task_type):
        """移除已完成的任务,释放内存"""
        try:
            # 从相应的任务列表中移除
            if task_type == "countdown" and task_info in self.countdown_tasks:
                self.countdown_tasks.remove(task_info)
            elif task_type == "reminder" and task_info in self.reminder_tasks:
                self.reminder_tasks.remove(task_info)
            
            # 销毁任务行
            if "row" in task_info:
                try:
                    task_info["row"].destroy()
                except Exception as e:
                    print(f"销毁任务行失败: {e}")
                del task_info["row"]
            
            # 清理任务对象中的引用
            if "future" in task_info:
                del task_info["future"]
            if "label" in task_info:
                del task_info["label"]
            
            # 延迟更新滚动区域,确保任务移除操作完成后再更新
            self.root.after(300, self.update_scrollable_frame)
        except Exception as e:
            print(f"移除任务失败: {e}")

    def save_tasks(self):
        """保存任务存档"""
        try:
            # 获取存档文件路径
            if getattr(sys, 'frozen', False):
                # 在打包环境中,使用可执行文件所在的目录
                script_dir = os.path.dirname(sys.executable)
            else:
                script_dir = os.path.dirname(os.path.abspath(__file__))
            save_path = os.path.join(script_dir, 'tasks.json')
            
            # 收集任务信息
            tasks_data = {
                "countdown_tasks": [],
                "reminder_tasks": []
            }
            
            # 保存倒计时任务
            import datetime
            save_time = datetime.datetime.now()
            for task in self.countdown_tasks:
                if task.get("running", False) and task.get("remaining_seconds", 0) > 0:
                    task_data = {
                        "name": task.get("name"),
                        "total_seconds": task.get("total_seconds"),
                        "remaining_seconds": task.get("remaining_seconds"),
                        "type": "countdown",
                        "save_time": save_time.isoformat()
                    }
                    tasks_data["countdown_tasks"].append(task_data)
            
            # 保存提醒任务
            for task in self.reminder_tasks:
                if task.get("running", False) and task.get("remaining_seconds", 0) > 0:
                    task_data = {
                        "name": task.get("name"),
                        "target_time": task.get("target_time").isoformat() if "target_time" in task else None,
                        "remaining_seconds": task.get("remaining_seconds"),
                        "type": "reminder",
                        "save_time": save_time.isoformat()
                    }
                    tasks_data["reminder_tasks"].append(task_data)
            
            # 保存到文件
            with open(save_path, 'w', encoding='utf-8') as f:
                json.dump(tasks_data, f, ensure_ascii=False, indent=2)
            
        except Exception as e:
            print(f"保存任务失败: {e}")

    def load_tasks(self):
        """加载任务存档"""
        try:
            # 获取存档文件路径
            if getattr(sys, 'frozen', False):
                # 在打包环境中,使用可执行文件所在的目录
                script_dir = os.path.dirname(sys.executable)
            else:
                script_dir = os.path.dirname(os.path.abspath(__file__))
            save_path = os.path.join(script_dir, 'tasks.json')
            
            # 检查文件是否存在
            if not os.path.exists(save_path):
                return
            
            # 读取存档文件
            with open(save_path, 'r', encoding='utf-8') as f:
                tasks_data = json.load(f)
            
            # 加载倒计时任务
            import datetime
            current_time = datetime.datetime.now()
            
            for task_data in tasks_data.get("countdown_tasks", []):
                remaining_seconds = task_data.get("remaining_seconds", 0)
                save_time_str = task_data.get("save_time")
                
                # 计算实际剩余时间
                actual_remaining = remaining_seconds
                
                # 如果有保存时间,计算保存到现在的时间差
                if save_time_str:
                    try:
                        save_time = datetime.datetime.fromisoformat(save_time_str)
                        time_diff = (current_time - save_time).total_seconds()
                        # 减去保存到现在的时间差
                        actual_remaining = max(0, remaining_seconds - time_diff)
                    except Exception as e:
                        print(f"解析保存时间失败: {e}")
                
                # 检查是否超过10秒
                if actual_remaining <= 10:
                    actual_remaining = 0
                
                # 创建任务行
                task_row = ttk.Frame(self.scrollable_frame, style="Countdown.TFrame")
                task_row.pack(fill=tk.X, pady=0, ipady=8, padx=0)

                # 创建内部框架
                inner_frame = ttk.Frame(task_row, style="Countdown.TFrame")
                inner_frame.pack(fill=tk.X, expand=True, padx=5)
                
                # 配置布局
                inner_frame.columnconfigure(0, minsize=400)
                inner_frame.columnconfigure(1, minsize=150)
                inner_frame.columnconfigure(2, minsize=200)
                inner_frame.rowconfigure(0, weight=1)

                # 任务名称
                name_label = ttk.Label(inner_frame, text=f"[倒计提醒] {task_data.get('name')}", style="Countdown.TLabel", anchor=tk.W, width=30)
                name_label.grid(row=0, column=0, sticky="w", padx=5)

                # 检查是否已过期
                if actual_remaining <= 0:
                    # 已过期,显示时间到
                    remaining_label = ttk.Label(inner_frame, text="&#9989; 时间到!", style="Countdown.TLabel", anchor=tk.CENTER, width=10, foreground="#dc2626")
                    task_running = False
                else:
                    # 未过期,显示剩余时间
                    remaining_label = ttk.Label(inner_frame, text=self.format_time(actual_remaining), style="Countdown.TLabel", anchor=tk.CENTER, width=10)
                    task_running = True
                
                remaining_label.grid(row=0, column=1, sticky="we", padx=5)

                # 存储任务信息
                import datetime
                import time
                # 计算目标时间:当前时间 + 实际剩余时间
                target_time = datetime.datetime.now() + datetime.timedelta(seconds=actual_remaining)
                # 计算开始时间:当前时间 - (总时长 - 实际剩余时间)
                start_time = time.time() - (task_data.get('total_seconds', actual_remaining) - actual_remaining)
                task_info = {
                    "name": task_data.get('name'),
                    "total_seconds": task_data.get('total_seconds'),
                    "remaining_seconds": actual_remaining,
                    "target_time": target_time,
                    "start_time": start_time,
                    "thread": None,
                    "label": remaining_label,
                    "row": task_row,
                    "running": task_running
                }
                self.countdown_tasks.append(task_info)

                # 按钮区
                button_frame = ttk.Frame(inner_frame, style="Countdown.TFrame")
                button_frame.grid(row=0, column=2, sticky="we", padx=5)
                
                # 删除按钮
                delete_btn = ttk.Button(button_frame, text="删除", command=lambda r=task_row, info=task_info: self.delete_countdown(r, info), width=10)
                delete_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
                
                # 复制按钮
                copy_btn = ttk.Button(button_frame, text="复制", command=lambda info=task_info: self.copy_task(info), width=10, style="Copy.TButton")
                copy_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
            
            # 加载提醒任务
            for task_data in tasks_data.get("reminder_tasks", []):
                # 计算实际剩余时间
                import datetime
                target_time = datetime.datetime.fromisoformat(task_data.get('target_time')) if task_data.get('target_time') else None
                actual_remaining = 0
                
                if target_time:
                    time_diff = (target_time - current_time).total_seconds()
                    actual_remaining = max(0, time_diff)
                
                # 检查是否超过10秒
                if actual_remaining <= 10:
                    actual_remaining = 0
                
                # 创建任务行
                task_row = ttk.Frame(self.scrollable_frame, style="Reminder.TFrame")
                task_row.pack(fill=tk.X, pady=0, ipady=8, padx=0)

                # 创建内部框架
                inner_frame = ttk.Frame(task_row, style="Reminder.TFrame")
                inner_frame.pack(fill=tk.X, expand=True, padx=5)
                
                # 配置布局
                inner_frame.columnconfigure(0, minsize=400)
                inner_frame.columnconfigure(1, minsize=150)
                inner_frame.columnconfigure(2, minsize=200)
                inner_frame.rowconfigure(0, weight=1)

                # 任务名称
                name_label = ttk.Label(inner_frame, text=f"[定时提醒] {task_data.get('name')}", style="Reminder.TLabel", anchor=tk.W, width=30)
                name_label.grid(row=0, column=0, sticky="w", padx=5)

                # 检查是否已过期
                if actual_remaining <= 0:
                    # 已过期,显示时间到
                    remaining_label = ttk.Label(inner_frame, text="&#9989; 时间到!", style="Reminder.TLabel", anchor=tk.CENTER, width=10, foreground="#dc2626")
                    task_running = False
                else:
                    # 未过期,显示剩余时间
                    remaining_label = ttk.Label(inner_frame, text=self.format_time(actual_remaining), style="Reminder.TLabel", anchor=tk.CENTER, width=10)
                    task_running = True
                
                remaining_label.grid(row=0, column=1, sticky="we", padx=5)

                # 存储任务信息
                task_info = {
                    "name": task_data.get('name'),
                    "target_time": target_time,
                    "remaining_seconds": actual_remaining,
                    "thread": None,
                    "label": remaining_label,
                    "row": task_row,
                    "running": task_running
                }
                self.reminder_tasks.append(task_info)

                # 按钮区
                button_frame = ttk.Frame(inner_frame, style="Reminder.TFrame")
                button_frame.grid(row=0, column=2, sticky="we", padx=5)
                
                # 删除按钮
                delete_btn = ttk.Button(button_frame, text="删除", command=lambda r=task_row, info=task_info: self.delete_reminder(r, info), width=10)
                delete_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
                
                # 复制按钮
                copy_btn = ttk.Button(button_frame, text="复制", command=lambda info=task_info: self.copy_reminder(info), width=10, style="Copy.TButton")
                copy_btn.pack(side=tk.LEFT, padx=5, fill=tk.Y)
            
            # 更新滚动区域
            self.update_scrollable_frame()
            
        except Exception as e:
            print(f"加载任务失败: {e}")

    def exit_app(self):
        """从托盘退出应用"""
        # 停止任务更新线程
        self.running = False
        # 保存任务存档
        self.save_tasks()
        # 停止所有任务
        for task in self.countdown_tasks:
            task["running"] = False
        for task in self.reminder_tasks:
            task["running"] = False
        # 关闭悬浮窗
        self.hide_floating_window()
        # 停止托盘图标
        if self.tray_icon:
            self.tray_icon.stop()
            self.tray_icon = None  # 明确设置为 None
        # 关闭窗口
        self.root.destroy()

if __name__ == "__main__":
    # 检查是否已经有实例在运行
    if not singleton():
        # 已经有实例在运行,显示提示并退出
        import ctypes
        ctypes.windll.user32.MessageBoxW(0, "多任务倒计时工具已经在运行中!", "提示", 0)
        sys.exit()
    
    root = tk.Tk()
    app = CountdownApp(root)
    root.mainloop()

蓝奏云:下载:
https://wwbbs.lanzouq.com/iJqrl3k6d73i 密码:52pj    解压密码52pj
Terri 发表于 2026-3-5 11:43
 楼主| fboy19871218 发表于 2026-3-5 13:49
地球守护者 发表于 2026-3-5 12:12
楼层主人,100MB大小,使用蓝奏·云存储,非常可以,百度网盘。。。

谢谢建议,已新增~
冥界3大法王 发表于 2026-3-5 15:20
这两天醇熟无比的使用AI生产力爆棚了
俺编了数个软件
还有多款x64dbg插件
这个还是Python的。
加油,一起加油吧!
 楼主| fboy19871218 发表于 2026-3-5 15:37
冥界3大法王 发表于 2026-3-5 15:20
这两天醇熟无比的使用AI生产力爆棚了
俺编了数个软件
还有多款x64dbg插件

最近利用 TRAE 做了些日常使用工具,vscode里面也有这插件,不习惯
doudou77 发表于 2026-3-5 16:12
很好的工具
xjshuaishuai 发表于 2026-3-5 16:13
谢谢分享!
perse 发表于 2026-3-5 16:14
支持!!!
cnfhal666 发表于 2026-3-5 16:16
一直想搞个,感谢大佬分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-6-16 04:01

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表