用Python写一个事件提醒的脚本

文章目录

一、界面展示

二、脚本功能

1. 核心功能

2. 界面功能

3. 安全性功能

三、使用方法

四、代码实现

1. 类结构设计

2. 关键方法实现

a. 创建界面组件

b. 设置单次提醒

c. 设置重复提醒

d. 删除提醒

3. 关键技术点

a. 多线程处理

b. 定时器实现

c. 数据存储

4. 错误处理

五、完整代码

六、总结

七、注意事项

一、界面展示

二、脚本功能

1. 核心功能

单次提醒功能:在指定日期和时间弹出提醒
重复提醒功能:支持每天/每周/每月定时提醒
删除提醒功能:可以删除已设置的提醒
提醒列表显示:实时显示所有设置的提醒

2. 界面功能

使用选项卡分类显示不同类型的提醒设置
提供图形化界面输入
实时显示提醒列表
错误提示和成功确认提示

3. 安全性功能

输入验证:检查必填字段
时间验证:防止设置过去的时间
格式验证:确保日期和时间格式正确

三、使用方法

1. 单次提醒

2. 重复提醒设置

3. 删除提醒

四、代码实现

1. 类结构设计

class ReminderApp:
    def __init__(self):
        # 初始化主窗口
        self.root = tk.Tk()
        # 初始化提醒字典
        self.reminders = {}
        # 创建界面组件
        self.create_widgets()
        # 启动调度线程
        self.schedule_thread = threading.Thread(target=self.run_schedule, daemon=True)

2. 关键方法实现

a. 创建界面组件

def create_widgets(self):
    # 创建选项卡
    self.notebook = ttk.Notebook(self.root)
    # 创建单次提醒和重复提醒标签页
    self.single_frame = ttk.Frame(self.notebook)
    self.repeat_frame = ttk.Frame(self.notebook)
    # 创建提醒列表
    self.reminder_list = tk.Listbox(self.root)

b. 设置单次提醒

def set_single_reminder(self):
    # 获取用户输入
    date_str = self.date_entry.get()
    time_str = self.single_time_entry.get()
    message = self.single_message_entry.get()
    
    # 验证输入
    if not all([date_str, time_str, message]):
        messagebox.showerror("错误", "请填写所有字段")
        return
        
    try:
        # 创建定时器
        reminder_datetime = datetime.strptime(f"{date_str} {time_str}", 
                                           "%Y-%m-%d %H:%M")
        delay = (reminder_datetime - datetime.now()).total_seconds()
        timer = threading.Timer(delay, self.show_reminder, 
                              args=[message, reminder_id])
        
        # 保存提醒信息
        self.reminders[reminder_id] = {
            'datetime': reminder_datetime,
            'message': message,
            'timer': timer,
            'repeat': False
        }

c. 设置重复提醒

def set_repeat_reminder(self):
    # 获取用户输入
    time_str = self.repeat_time_entry.get()
    message = self.repeat_message_entry.get()
    repeat_type = self.repeat_type.get()
    
    try:
        # 根据重复类型设置调度任务
        if repeat_type == "daily":
            job = schedule.every().day.at(time_str).do(
                self.show_reminder, message, reminder_id)
        # 保存提醒信息
        self.reminders[reminder_id] = {
            'time': time_str,
            'message': message,
            'job': job,
            'repeat': True,
            'repeat_type': repeat_type
        }

d. 删除提醒

def delete_reminder(self):
    # 获取选中的提醒
    selection = self.reminder_list.curselection()
    if not selection:
        messagebox.showwarning("警告", "请先选择要删除的提醒")
        return
    
    # 删除提醒
    reminder_id = list(self.reminders.keys())[selection[0]]
    self.remove_reminder(reminder_id)
    self.update_reminder_list()

3. 关键技术点

a. 多线程处理

# 使用守护线程运行调度器
self.schedule_thread = threading.Thread(target=self.run_schedule, daemon=True)
self.schedule_thread.start()

b. 定时器实现

# 单次提醒使用 threading.Timer
timer = threading.Timer(delay, self.show_reminder, args=[message, reminder_id])

# 重复提醒使用 schedule 库
schedule.every().day.at(time_str).do(self.show_reminder, message, reminder_id)

c. 数据存储

# 使用字典存储所有提醒
self.reminders = {
    'reminder_id': {
        'datetime': datetime_obj,  # 对于单次提醒
        'time': time_str,         # 对于重复提醒
        'message': message,
        'timer/job': timer_or_job_obj,
        'repeat': boolean,
        'repeat_type': type_str   # 对于重复提醒
    }
}

4. 错误处理

try:
    # 时间格式转换
    reminder_datetime = datetime.strptime(f"{date_str} {time_str}", 
                                        "%Y-%m-%d %H:%M")
    # 验证时间是否有效
    if reminder_datetime < datetime.now():
        messagebox.showerror("错误", "不能设置过去的时间")
        return
except ValueError:
    messagebox.showerror("错误", "日期或时间格式错误")

五、完整代码

import tkinter as tk
from tkinter import messagebox, ttk
import time
import schedule
import threading
from datetime import datetime, timedelta
import platform
import os

# 根据操作系统选择声音模块
if platform.system() == 'Windows':
    import winsound


    def play_alert():
        winsound.Beep(1000, 1000)  # 频率1000Hz,持续1000毫秒
else:
    def play_alert():
        os.system('play -nq -t alsa synth 1 sine 440')  # Linux系统下的提示音


class ReminderApp:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("定时提醒")
        self.root.geometry("400x600")

        # 存储所有提醒的字典
        self.reminders = {}

        # 声音开关变量
        self.sound_enabled = tk.BooleanVar(value=True)

        # 创建输入框和按钮
        self.create_widgets()

        # 创建一个线程来运行调度器
        self.schedule_thread = threading.Thread(target=self.run_schedule, daemon=True)
        self.schedule_thread.start()

    def create_widgets(self):
        # 创建notebook用于切换不同类型的提醒设置
        self.notebook = ttk.Notebook(self.root)
        self.notebook.pack(pady=5, expand=True, fill="both")

        # 单次提醒标签页
        self.single_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.single_frame, text="单次提醒")

        # 重复提醒标签页
        self.repeat_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.repeat_frame, text="重复提醒")

        # 设置单次提醒的控件
        self.setup_single_reminder_widgets()

        # 设置重复提醒的控件
        self.setup_repeat_reminder_widgets()

        # 声音控制区域
        sound_frame = ttk.LabelFrame(self.root, text="声音设置")
        sound_frame.pack(pady=5, padx=5, fill="x")

        # 声音开关复选框
        self.sound_checkbox = tk.Checkbutton(sound_frame, text="启用提醒声音",
                                             variable=self.sound_enabled)
        self.sound_checkbox.pack(side=tk.LEFT, padx=5)

        # 测试声音按钮
        self.test_sound_button = tk.Button(sound_frame, text="测试提醒声音",
                                           command=self.test_sound)
        self.test_sound_button.pack(side=tk.RIGHT, padx=5)

        # 提醒列表框架
        list_frame = ttk.LabelFrame(self.root, text="提醒列表")
        list_frame.pack(pady=5, padx=5, fill="both", expand=True)

        # 提醒列表
        self.reminder_list = tk.Listbox(list_frame, width=50, height=10)
        self.reminder_list.pack(pady=5, padx=5, fill="both", expand=True)

        # 删除提醒按钮
        self.delete_button = tk.Button(list_frame, text="删除选中的提醒",
                                       command=self.delete_reminder)
        self.delete_button.pack(pady=5)

    def setup_single_reminder_widgets(self):
        # 日期输入
        date_frame = ttk.Frame(self.single_frame)
        date_frame.pack(pady=5, fill="x")
        ttk.Label(date_frame, text="日期 (YYYY-MM-DD):").pack(side=tk.LEFT, padx=5)
        self.date_entry = ttk.Entry(date_frame)
        self.date_entry.pack(side=tk.LEFT, expand=True, fill="x", padx=5)
        self.date_entry.insert(0, datetime.now().strftime("%Y-%m-%d"))

        # 时间输入
        time_frame = ttk.Frame(self.single_frame)
        time_frame.pack(pady=5, fill="x")
        ttk.Label(time_frame, text="时间 (HH:MM):").pack(side=tk.LEFT, padx=5)
        self.single_time_entry = ttk.Entry(time_frame)
        self.single_time_entry.pack(side=tk.LEFT, expand=True, fill="x", padx=5)

        # 提醒内容输入
        message_frame = ttk.Frame(self.single_frame)
        message_frame.pack(pady=5, fill="x")
        ttk.Label(message_frame, text="提醒内容:").pack(side=tk.LEFT, padx=5)
        self.single_message_entry = ttk.Entry(message_frame)
        self.single_message_entry.pack(side=tk.LEFT, expand=True, fill="x", padx=5)

        # 设置提醒按钮
        self.single_set_button = ttk.Button(self.single_frame, text="设置单次提醒",
                                            command=self.set_single_reminder)
        self.single_set_button.pack(pady=10)

    def setup_repeat_reminder_widgets(self):
        # 时间输入
        time_frame = ttk.Frame(self.repeat_frame)
        time_frame.pack(pady=5, fill="x")
        ttk.Label(time_frame, text="时间 (HH:MM):").pack(side=tk.LEFT, padx=5)
        self.repeat_time_entry = ttk.Entry(time_frame)
        self.repeat_time_entry.pack(side=tk.LEFT, expand=True, fill="x", padx=5)

        # 提醒内容输入
        message_frame = ttk.Frame(self.repeat_frame)
        message_frame.pack(pady=5, fill="x")
        ttk.Label(message_frame, text="提醒内容:").pack(side=tk.LEFT, padx=5)
        self.repeat_message_entry = ttk.Entry(message_frame)
        self.repeat_message_entry.pack(side=tk.LEFT, expand=True, fill="x", padx=5)

        # 重复类型选择
        repeat_type_frame = ttk.LabelFrame(self.repeat_frame, text="重复类型")
        repeat_type_frame.pack(pady=5, padx=5, fill="x")

        self.repeat_type = tk.StringVar(value="daily")
        repeat_options = [
            ("每天", "daily"),
            ("每周", "weekly"),
            ("每月", "monthly")
        ]

        for text, value in repeat_options:
            ttk.Radiobutton(repeat_type_frame, text=text, variable=self.repeat_type,
                            value=value).pack(side=tk.LEFT, padx=10)

        # 设置提醒按钮
        self.repeat_set_button = ttk.Button(self.repeat_frame, text="设置重复提醒",
                                            command=self.set_repeat_reminder)
        self.repeat_set_button.pack(pady=10)

    def show_reminder(self, message, reminder_id):
        # 如果启用了声音,播放提示音
        if self.sound_enabled.get():
            sound_thread = threading.Thread(target=play_alert)
            sound_thread.start()

        # 显示消息框
        messagebox.showinfo("提醒", message)

        # 如果是单次提醒,显示后删除
        if reminder_id in self.reminders and not self.reminders[reminder_id].get('repeat'):
            self.remove_reminder(reminder_id)
            self.update_reminder_list()

    def test_sound(self):
        """测试提醒声音"""
        if self.sound_enabled.get():
            play_alert()

    def set_single_reminder(self):
        date_str = self.date_entry.get()
        time_str = self.single_time_entry.get()
        message = self.single_message_entry.get()

        if not all([date_str, time_str, message]):
            messagebox.showerror("错误", "请填写所有字段")
            return

        try:
            reminder_datetime = datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M")
            if reminder_datetime < datetime.now():
                messagebox.showerror("错误", "不能设置过去的时间")
                return

            reminder_id = f"single_{len(self.reminders)}"
            delay = (reminder_datetime - datetime.now()).total_seconds()

            timer = threading.Timer(delay, self.show_reminder, args=[message, reminder_id])
            timer.start()

            self.reminders[reminder_id] = {
                'datetime': reminder_datetime,
                'message': message,
                'timer': timer,
                'repeat': False
            }

            self.update_reminder_list()
            messagebox.showinfo("成功", f"提醒已设置在 {date_str} {time_str}")

        except ValueError:
            messagebox.showerror("错误", "日期或时间格式错误")

    def set_repeat_reminder(self):
        time_str = self.repeat_time_entry.get()
        message = self.repeat_message_entry.get()
        repeat_type = self.repeat_type.get()

        if not all([time_str, message]):
            messagebox.showerror("错误", "请填写所有字段")
            return

        try:
            reminder_id = f"repeat_{len(self.reminders)}"

            if repeat_type == "daily":
                job = schedule.every().day.at(time_str).do(
                    self.show_reminder, message, reminder_id)
            elif repeat_type == "weekly":
                job = schedule.every().week.at(time_str).do(
                    self.show_reminder, message, reminder_id)
            elif repeat_type == "monthly":
                job = schedule.every().month.at(time_str).do(
                    self.show_reminder, message, reminder_id)

            self.reminders[reminder_id] = {
                'time': time_str,
                'message': message,
                'job': job,
                'repeat': True,
                'repeat_type': repeat_type
            }

            self.update_reminder_list()
            messagebox.showinfo("成功", f"重复提醒已设置")

        except schedule.ScheduleValueError:
            messagebox.showerror("错误", "时间格式错误,请使用HH:MM格式")

    def delete_reminder(self):
        selection = self.reminder_list.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择要删除的提醒")
            return

        reminder_id = list(self.reminders.keys())[selection[0]]
        self.remove_reminder(reminder_id)
        self.update_reminder_list()
        messagebox.showinfo("成功", "提醒已删除")

    def remove_reminder(self, reminder_id):
        if reminder_id in self.reminders:
            reminder = self.reminders[reminder_id]
            if reminder.get('repeat'):
                schedule.cancel_job(reminder['job'])
            else:
                reminder['timer'].cancel()
            del self.reminders[reminder_id]

    def update_reminder_list(self):
        self.reminder_list.delete(0, tk.END)
        for reminder_id, reminder in self.reminders.items():
            if reminder.get('repeat'):
                text = f"重复提醒: {reminder['time']} - {reminder['message']} ({reminder['repeat_type']})"
            else:
                text = f"单次提醒: {reminder['datetime'].strftime('%Y-%m-%d %H:%M')} - {reminder['message']}"
            self.reminder_list.insert(tk.END, text)

    def run_schedule(self):
        while True:
            schedule.run_pending()
            time.sleep(1)

    def run(self):
        self.root.mainloop()


if __name__ == "__main__":
    app = ReminderApp()
    app.run()

六、总结

脚本通过组合使用多线程、定时器、图形界面和事件调度等技术,实现一个功能完整的定时提醒系统。

七、注意事项

这个脚本仍然需要保持运行状态才能实现提醒功能。如果你需要在计算机启动时自动运行,可以将其设置为开机启动项。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

穿梭的编织者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值