如何实现PySimpleGUI的SystemTray.notify非阻塞/异步调用?
解决方案
现有实现的核心问题
- 仅存储单个弹窗实例,新通知生成时会覆盖旧实例引用,触发Ok事件时仅能关闭最新弹窗,旧弹窗无法被正常管理
- 事件循环中重复调用
tray.read()和sg.read_all_windows(),两处timeout配置会导致事件响应出现延迟甚至阻塞 create_popup依赖全局变量myresult,多通知场景下会出现内容错乱- 多通知未做位置偏移,新弹窗会完全覆盖旧弹窗
可行实现方案
不需要引入多线程,直接通过PySimpleGUI原生的多窗口事件管理机制就可以实现非阻塞的多通知驻留效果,修改后代码如下:
import PySimpleGUI as sg import random # 存储所有活跃的通知窗口 active_popups = [] def create_popup(title, content): dx, dy = sg.SYSTEM_TRAY_WIN_MARGINS screen_res_x, screen_res_y = sg.Window.get_screen_size() layout = [ [sg.Text(title, font=("微软雅黑", 10, "bold"))], [sg.Text(content, font=("微软雅黑", 9))], [sg.Button('Ok', size=(10, 1))] ] window = sg.Window( "通知", layout, keep_on_top=True, no_titlebar=True, grab_anywhere=True, finalize=True, alpha_channel=0.95 # 可调整透明度优化视觉效果 ) width, height = window.size # 多通知自动向上偏移,避免重叠 offset_y = len(active_popups) * (height + 10) window.move(screen_res_x - width - dx, screen_res_y - height - dy - offset_y) return window # 初始化系统托盘 tray = sg.SystemTray(menu=['menu', ['Open', 'Exit']], filename='icon.ico') # 自行替换图标路径 def query(): # 你的MySQL查询逻辑,这里仅做示例返回 # 实际使用时替换为你的数据库查询代码,返回 (通知ID, 通知标题, 通知内容) return (random.randint(1, 1000), "通知标题测试", "通知内容测试") last_notification_id = 0 while True: # 统一读取所有事件:托盘+所有通知窗口,非阻塞 win, event, values = sg.read_all_windows(timeout=10000) # 处理退出逻辑 if event in (sg.WINDOW_CLOSED, 'Exit'): break # 处理托盘菜单事件 if win == tray: if event == 'Open': sg.popup('后续功能开发中') # 处理通知窗口的Ok按钮事件 if event == 'Ok': win.close() if win in active_popups: active_popups.remove(win) # 轮询查询新通知 current_notification = query() current_notification_id = current_notification[0] if current_notification_id > last_notification_id: # 生成新通知窗口加入活跃列表 new_popup = create_popup(current_notification[1], current_notification[2]) active_popups.append(new_popup) last_notification_id = current_notification_id # 退出时关闭所有残留窗口 for popup in active_popups: popup.close() tray.close()
关键改动说明
- 用
active_popups列表统一管理所有驻留的通知窗口,支持同时存在多条通知 - 统一使用
sg.read_all_windows()处理所有事件,全程非阻塞,不会卡住新通知的查询和推送 - 新通知生成时自动向上偏移位置,避免重叠覆盖,视觉上更清晰
- 所有窗口操作都在主线程事件循环中执行,避免跨线程操作GUI导致的异常问题
内容的提问来源于stack exchange,提问作者Biorez
相关产品推荐
相关产品推荐

