You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在指定时间后台运行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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 21:54:03