Python使用pystray时无法正常退出程序的问题求助
问题描述
尝试用exit()、exit(0)、sys.exit()(已导入sys)及quit()退出pystray托盘程序均失败,调用时会抛出SystemExit异常;使用icon.stop()仅能终止托盘图标,后续代码需等托盘退出后才执行,无法直接退出整个程序。
尝试1:使用exit()的代码
from pystray import MenuItem as item import pystray from PIL import Image while True: def show(): exit() image = Image.open("TrayIcon.jpg") menu = (item('exit', show),) icon = pystray.Icon("name", image, "title", menu) icon.run() print('running...')
报错信息
An error occurred when calling message handler Traceback (most recent call last): File "D:\py3.7\lib\site-packages\pystray\_win32.py", line 402, in _dispatcher uMsg, lambda w, l: 0)(wParam, lParam) or 0) File "D:\py3.7\lib\site-packages\pystray\_win32.py", line 213, in _on_notify descriptors[index - 1](self) File "D:\py3.7\lib\site-packages\pystray\_base.py", line 324, in inner callback(self) File "D:\py3.7\lib\site-packages\pystray\_base.py", line 449, in __call__ return self._action(icon, self) File "D:\py3.7\lib\site-packages\pystray\_base.py", line 544, in wrapper0 return action() File "C:/Users/admin/AppData/Roaming/JetBrains/PyCharmCE2022.1/scratches/scratch.py", line 9, in show exit() File "D:\py3.7\lib\_sitebuiltins.py", line 26, in __call__ raise SystemExit(code) SystemExit: None
尝试2:使用icon.stop()的代码
from pystray import MenuItem as item import pystray from PIL import Image def show(): icon.stop() image = Image.open("TrayIcon.jpg") menu = (item('exit', show),) icon = pystray.Icon("name", image, "title", menu) icon.run() while True: print('running...')
现象
托盘图标显示期间无running...输出,必须退出托盘后才开始打印,且无法直接退出整个程序。
解决方案
1. 正确实现程序退出(结合icon.stop()与sys.exit())
pystray的icon.run()是阻塞式方法,会启动消息循环。直接在菜单回调中调用exit()会在消息处理线程中抛出异常,导致报错。正确做法是先停止托盘,再退出程序,同时将后台任务放到守护线程中运行。
修改后代码:
from pystray import MenuItem as item import pystray from PIL import Image import sys import threading import time def background_task(): # 后台运行的任务逻辑 while True: print('running...') time.sleep(1) # 控制打印频率 def on_exit(icon, item): # 先终止托盘消息循环 icon.stop() # 退出整个程序 sys.exit() # 启动后台守护线程,主线程退出时自动终止 threading.Thread(target=background_task, daemon=True).start() image = Image.open("TrayIcon.jpg") menu = (item('exit', on_exit),) icon = pystray.Icon("name", image, "title", menu) icon.run()
2. 关键要点
icon.run()会阻塞主线程,因此后台任务必须放在守护线程中,避免主线程被卡住。- 菜单回调中先执行
icon.stop()停止托盘消息循环,再调用sys.exit()退出程序,避免在消息处理线程中抛出异常。 - 不要将
icon.run()放入while True循环,这会导致托盘被反复创建,造成逻辑混乱。
内容的提问来源于stack exchange,提问作者Danhui Xu
相关产品推荐
相关产品推荐

