最近,在实现TodoList应用最小化到系统托盘的功能时,踩了几个坑,记录一下。

这个功能其实挺常见的:用户点击应用右上角的关闭按钮,应用不会直接退出,而是最小化到系统托盘,在后台继续运行。
这么做的好处也很直观——不占用桌面空间,同时保持后台运行,避免消息提醒失效。
不过真落地实现的时候,还是有几个需要注意的地方,下面展开聊聊~
一开始让 AI 帮忙写,结果跑不起来。后来参考了 AI 提及的这篇文章:终极系统托盘集成指南:使用 pywebview 创建后台运行的桌面应用[1],才把功能调通。
webview_process = Nonedefrun_webview(): webview.create_window('Webview', 'https://pywebview.flowrl.com/hello') webview.start()if __name__ == '__main__':defstart_webview_process():global webview_process webview_process = Process(target=run_webview) webview_process.start()defon_open(icon, item):global webview_processifnot webview_process.is_alive(): start_webview_process()defon_exit(icon, item): icon.stop() start_webview_process() image = Image.open('demo.png') menu = Menu(MenuItem('Open', on_open), MenuItem('Exit', on_exit)) icon = Icon('Pystray', image, menu=menu) icon.run() webview_process.terminate()整体思路是用到了 pystray 这个库:
icon.run() 保持应用在后台持续运行create_window 提取为独立方法,方便重复调用webview_process 管理子进程,点击“打开”时判断是否存活,避免重复启动icon.stop(),托盘图标才会退出,应用才算真正关闭在 MenuItem 中设置 default=True 即可实现单击托盘图标时触发打开操作。
这里有个小插曲:我用 DeepSeek 咨询时,它推荐的 default_action 函数一直不生效。后来换 Gemini,给出的方案是直接加 default=True,看引用来源是 Stack Overflow 上的回答。
估计这个问题在国内社区讨论不多,导致 DeepSeek 的训练数据里没覆盖到。
menu = Menu(MenuItem('打开应用', on_open, default=True), MenuItem('彻底退出', on_exit))这个问题也是靠 Gemini 解决的。DeepSeek 给的方案偏复杂,就没继续折腾。
if __name__ == '__main__':# 用于解决打包后的多进程问题 multiprocessing.freeze_support()# 其他代码重复打开的原因是子进程重新执行了 main 块。两个 AI 分析的根因基本一致:
主进程启动 ↓执行 if __name__ == '__main__': 块 ↓创建 webview_process (子进程A) ↓webview_process.start() 触发: ├─ 创建新进程 ├─ 重新导入 main.py ├─ 子进程A执行 if __name__ == '__main__'? │ └─ 是的!因为这是新进程的入口 └─ 再次打印 "启动任务提醒服务..." (第2次) ↓主进程继续执行 icon.run() ↓icon.run() 阻塞主进程这个可以通过前端自定义弹窗 + 后端监听关闭事件来实现。不过 pywebview 本身提供了默认实现,我就直接偷懒用了:
webview.create_window('TodoList', frontend_path, js_api=api, width=1400, height=900, text_select=True, resizable=True, confirm_close=True# 增加该配置项)另外,pywebview 的关闭弹窗支持中文化配置,但遗憾的是不支持动态切换。如果后续英文用户不多,可能就不折腾了~
# 定义本地化字符串字典chinese_localization = {'global.quitConfirmation': '温馨提示:\n关闭后,程序将最小化到系统托盘以保持消息后台提醒。\n如需彻底关闭,请在托盘右键退出~','global.ok': '确定','global.cancel': '取消'}webview.start(bind, backend.globals.window, private_mode=False, ssl=True, debug=False, localization= chinese_localization)好了,以上就是今天分享的内容。我是唐叔,欢迎三连~
终极系统托盘集成指南:使用 pywebview 创建后台运行的桌面应用: https://blog.csdn.net/gitblog_00368/article/details/151036769