线程运行时访问内部更新变量:PySimpleGUI进度条适配难题
解决方案
核心思路
- 解决进度条实时更新问题:给
window.read()添加超时时间,让GUI事件循环能定期轮询进度状态;同时用write_event_value主动向GUI发送进度更新事件,避免阻塞。 - 实现函数跨环境兼容:给通用函数设计可选的进度更新接口,GUI环境传入GUI更新逻辑,终端环境默认使用终端打印,彻底避免函数直接依赖PySimpleGUI对象。
重构后的完整代码
import threading import time import PySimpleGUI as sg def general_long_function(progress_updater=None): # 默认进度更新器:终端打印进度信息 def default_updater(bar_idx, text, current, max_val): print(f"进度条{bar_idx}: {text} | {current}/{max_val}") updater = progress_updater or default_updater # 初始化进度条状态 updater(0, "Do Top loop", 0, 10) updater(1, "Inner Loop item 0", 0, 10) for i in range(10): updater(0, "Do Top loop", i+1, 10) for k in range(10): updater(1, f"Inner Loop item {k}", k+1, 10) print(f'i: {i} , k:{k}, currTest: Inner Loop item {k}') time.sleep(.02) # 任务结束后清空进度条 updater(0, "", 0, 10) updater(1, "", 0, 10) print('finished') ############################# GUI 代码 ############################# def the_gui(): sg.theme('Light Brown 3') layout = [ [sg.Text('Click Go to start a long-running function call')], [sg.Text(size=(25, 1), key='-OUTPUT0-')], [sg.Text(size=(25, 1), key='-OUTPUT1-')], [sg.Text(size=(25, 1), key='-OUTPUT2-')], [sg.ProgressBar(10, 'h', size=(30, 20), k='-PROGBAR0-')], [sg.ProgressBar(10, 'h', size=(30, 20), k='-PROGBAR1-')], [sg.ProgressBar(100, 'h', size=(30, 20), k='-PROGBAR2-')], [sg.Button('Go'), sg.Button('Popup'), sg.Button('Exit')], ] window = sg.Window('Multithreaded Window', layout) # GUI专用进度更新器:通过write_event_value向主循环发送进度事件 def gui_progress_updater(bar_idx, text, current, max_val): window.write_event_value('-PROGRESS_UPDATE-', (bar_idx, text, current, max_val)) while True: # 设置10ms超时,让循环定期执行,实现进度实时更新 event, values = window.read(timeout=10) if event in (sg.WIN_CLOSED, 'Exit'): print('exiting...') break if event == 'Go': print('adding thread') thread_id = threading.Thread( target=general_long_function, args=(gui_progress_updater,), daemon=True ) thread_id.start() if event == 'Popup': sg.popup_non_blocking('This is a popup showing that the GUI is running', grab_anywhere=True) if event == '-PROGRESS_UPDATE-': bar_idx, text, current, max_val = values[event] window[f'-PROGBAR{bar_idx}-'].update(current, max_val) window[f'-OUTPUT{bar_idx}-'].update(text) window.close() if __name__ == '__main__': # 可切换运行模式:注释掉一行即可 # general_long_function() # 终端模式运行 the_gui() # GUI模式运行 print('Exiting Program')
关键改进点说明
- 进度逻辑解耦:通用函数不再依赖全局变量或PySimpleGUI对象,通过可选参数
progress_updater接收更新逻辑,终端环境默认用打印,GUI环境传入专用更新函数,完美实现跨环境兼容。 - 实时进度刷新:GUI事件循环通过
window.read(timeout=10)定期执行,配合write_event_value主动发送进度事件,彻底解决原代码中进度条仅在用户操作时更新的问题。 - 代码简洁可靠:移除了冗余的全局变量,改用事件传递进度数据,逻辑更清晰,维护成本更低。
独立运行函数的方式
直接调用general_long_function()即可,此时会默认使用终端打印进度信息,无需依赖PySimpleGUI:
if __name__ == '__main__': general_long_function() # 终端模式运行
内容的提问来源于stack exchange,提问作者gerrgheiser
相关产品推荐
相关产品推荐

