如何在指定时间后台运行Python脚本实现关闭应用仍生效的桌面通知
桌面通知工具关端仍生效实现方案
核心问题说明
你当前的代码属于单进程GUI应用,主窗口销毁后整个程序进程就会终止,内置的定时逻辑也会随之销毁,自然无法在关闭程序后继续推送通知。解决方案直接依托系统原生的定时调度能力即可,无需额外部署后台服务。
实现步骤
- 提交通知任务时,将通知标题、内容、触发时间持久化存储到本地JSON文件
- 调用对应系统的定时任务创建命令,指定到点触发独立的通知脚本
- 通知脚本读取本地存储的通知信息,调用plyer完成推送后清理对应任务记录
代码修改示例
1. 主GUI程序修改
import tkinter as tk from tkinter import * from tkinter import ttk,messagebox from PIL import Image,ImageTk import json import os from datetime import datetime, timedelta import subprocess root=tk.Tk() root.geometry("720x500") root.resizable(0,0) root.title('DESKTOP NOTIFIER') # 存储路径配置 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) NOTIFY_STORAGE = os.path.join(BASE_DIR, "pending_notify.json") TRIGGER_SCRIPT = os.path.join(BASE_DIR, "trigger_notification.py") ICON_PATH = os.path.join(BASE_DIR, "favicon (1).ico") def notify(): title1=entry1.get(1.0,END).strip() message1=entry2.get(1.0,END).strip() time_min=entry3.get(1.0,END).strip() if not title1 or not message1 or not time_min: messagebox.showerror('Alert','所有字段都不能为空') return try: delay_min = int(time_min) except ValueError: messagebox.showerror('Alert','时间必须是数字') return # 计算触发时间 trigger_time = datetime.now() + timedelta(minutes=delay_min) task_id = f"notify_{int(trigger_time.timestamp())}" # 存储通知信息 notify_data = { "task_id": task_id, "title": title1, "content": message1, "icon": ICON_PATH } # 写入存储文件 if os.path.exists(NOTIFY_STORAGE): with open(NOTIFY_STORAGE, "r", encoding="utf-8") as f: all_tasks = json.load(f) else: all_tasks = [] all_tasks.append(notify_data) with open(NOTIFY_STORAGE, "w", encoding="utf-8") as f: json.dump(all_tasks, f, ensure_ascii=False, indent=2) # 创建Windows定时任务,其他系统替换对应命令即可 time_str = trigger_time.strftime("%H:%M") date_str = trigger_time.strftime("%Y/%m/%d") cmd = [ "schtasks", "/create", "/tn", task_id, "/tr", f'pythonw "{TRIGGER_SCRIPT}" {task_id}', "/sc", "once", "/st", time_str, "/sd", date_str, "/f" ] try: subprocess.run(cmd, check=True, capture_output=True) messagebox.showinfo("成功", f"定时通知已设置,将在{delay_min}分钟后推送,关闭程序不影响生效") # 清空输入框 entry1.delete(1.0, END) entry2.delete(1.0, END) entry3.delete(1.0, END) except Exception as e: messagebox.showerror("错误", f"创建定时任务失败:{str(e)}") # 原有控件代码保持不变 label0=Label(root,text='DESKTOP NOTIFIER',font=('lemonmilk',20)).place(x=250,y=20) label3=Label(root,text='min',font=('lemonmilk 15')).place(x=275,y=310) #entry1 entry1=Text(root,width=55,height=2) entry1.place(x=200,y=130) label1=Label(root,text='TITLE: ',font=('lemonmilk',15)).place(x=120,y=133) #entry2 entry2=Text(root,width=55,height=5) entry2.place(x=200,y=195) label2=Label(root,text='DESCRIPITION: ',font=('lemonmilk',15)).place(x=35,y=200) #entry3 entry3=Text(root,width=6,height=1,font=('lemonmilk')) entry3.place(x=200,y=310) label33=Label(root,text=' SET TIME: ',font=('lemonmilk',15)).place(x=70,y=310) #buttons button1=Button(root,text='NOTIFY ME!',width=15,height=4,font=('lemonmilk 13 bold'),command=notify).place(x=460,y=370) button2=Button(root,text='QUIT APPLICATION',width=20,height=4,font=('lemonmilk 13 bold'),command=root.destroy).place(x=150,y=370) root.mainloop()
2. 新增独立通知触发脚本trigger_notification.py
import sys import json import os from plyer import notification BASE_DIR = os.path.dirname(os.path.abspath(__file__)) NOTIFY_STORAGE = os.path.join(BASE_DIR, "pending_notify.json") if __name__ == "__main__": if len(sys.argv) < 2: sys.exit(1) task_id = sys.argv[1] if not os.path.exists(NOTIFY_STORAGE): sys.exit(0) with open(NOTIFY_STORAGE, "r", encoding="utf-8") as f: all_tasks = json.load(f) remain_tasks = [] target_task = None for task in all_tasks: if task["task_id"] == task_id: target_task = task else: remain_tasks.append(task) if target_task: # 发送通知 notification.notify( title=target_task["title"], message=target_task["content"], app_icon=target_task["icon"], timeout=15 ) # 更新存储文件,删除已触发的任务 with open(NOTIFY_STORAGE, "w", encoding="utf-8") as f: json.dump(remain_tasks, f, ensure_ascii=False, indent=2) # 删除已完成的系统定时任务(Windows) import subprocess subprocess.run(["schtasks", "/delete", "/tn", task_id, "/f"], capture_output=True)
注意事项
- Windows环境下需确保Python已经添加到系统环境变量中,否则定时任务无法找到pythonw命令
- 图标路径建议用绝对路径,避免定时任务执行时找不到资源
- 如果需要适配Linux或macOS,只需将创建、删除定时任务的部分替换为crontab(Linux)或launchd(macOS)的对应命令即可
- 要是不需要跨平台,也可以用
APScheduler结合后台守护进程的方案实现,但相比系统原生定时任务,后者资源占用更低、稳定性更高
内容的提问来源于stack exchange,提问作者kushagra
相关产品推荐
相关产品推荐

