如何使用pystray根据ping值动态更改系统托盘图标?
解决pystray系统托盘图标无法根据ping结果动态更新的问题
问题根源
你的代码每次循环都新建pystray.Icon实例并调用icon.run(),但run()是阻塞式的事件循环方法,第一次执行后程序就会停在这个方法里,无法进入下一次循环,自然没法更新图标。
修正方案
正确思路是只初始化一次托盘图标,在单独线程中执行ping检测和图标更新逻辑,通过修改已有图标的image属性实现动态切换:
import pystray import ping3 import threading import time from PIL import Image # 提前加载所有图标(替换为你的图标文件路径) white_icon = Image.open("white.png") green_icon = Image.open("green.png") yellow_icon = Image.open("yellow.png") orange_icon = Image.open("orange.png") red_icon = Image.open("red.png") def update_tray_icon(icon): while True: p_out = ping3.ping("google.com", unit="ms") # 处理ping返回None的情况(网络不通时会返回空值) if p_out is None: current_icon = red_icon elif p_out == 0: current_icon = white_icon elif p_out >= 999: current_icon = red_icon else: print(f'\n{p_out:4.0f}', end='') if p_out <= 50: current_icon = green_icon elif p_out <= 60: current_icon = yellow_icon elif p_out < 100: current_icon = orange_icon else: current_icon = red_icon # 更新图标并通知系统刷新 icon.image = current_icon icon.update() # 控制检测间隔,按需调整 time.sleep(2) # 初始化托盘图标,默认用绿色图标 icon = pystray.Icon("ping_monitor", green_icon) # 启动ping检测的守护线程,不阻塞主事件循环 threading.Thread(target=update_tray_icon, args=(icon,), daemon=True).start() # 启动托盘图标事件循环 icon.run()
关键细节
- 用PIL提前加载所有图标资源,避免每次切换时重复读取文件
- 守护线程负责ping检测和图标更新,不影响pystray的主事件循环
- 修改
icon.image后调用icon.update(),强制系统刷新托盘显示 - 增加
time.sleep()控制检测频率,避免过度占用资源 - 额外处理了ping返回
None的异常场景(比如网络断开)
内容的提问来源于stack exchange,提问作者Douglas Silva
相关产品推荐
相关产品推荐

