如何正确使用pystray中的run_detached()和stop()方法
解决方案
不建议直接修改pystray库源码,可选择以下两种稳定的临时方案:
方案1:给run_detached传入空setup参数(无需修改源码)
你遇到的NameError: name 'setup' is not defined是因为run_detached方法的参数传递逻辑存在缺陷,不需要修改源码,只需要调用时主动传入一个空的setup函数即可解决报错:
# 其他代码保持不变,最后一行替换为以下内容 icon.run_detached(setup=lambda *args: None)
针对stop失效、图标冻结的问题,修改quit_window函数,手动触发图标隐藏即可:
def quit_window(icon): icon.stop() icon.visible = False
方案2:自行创建守护线程运行run()(更稳定,推荐)
由于官方run_detached本身存在未修复的bug,更稳妥的方式是放弃使用run_detached,自己启动一个守护线程运行阻塞的run()方法,天然实现非阻塞效果,且stop方法可以完全正常工作:
import pystray from pystray import MenuItem as item from PIL import Image import threading def show_window(icon): print('Test') def quit_window(icon): icon.stop() icon_path = 'icon.ico' image = Image.open(icon_path) menu = pystray.Menu(item('Show', show_window, default=True), item('Quit', quit_window)) icon = pystray.Icon("name", image, "My System Tray Icon", menu) # 启动守护线程运行托盘逻辑,主线程不会被阻塞 tray_thread = threading.Thread(target=icon.run, daemon=True) tray_thread.start() # 后续可正常编写主线程的其他业务逻辑,不会被阻塞
该方案不需要修改库源码,点击Quit后托盘图标会正常消失,线程也会正确终止,没有冻结残留问题。
注意:如果你的程序还接入了其他UI框架(比如Tkinter、PyQt),需要保证框架的消息循环和pystray的线程互不冲突,不要在非主线程操作UI元素。
内容的提问来源于stack exchange,提问作者JonLord
相关产品推荐
相关产品推荐

