Python PySimpleGUI 进度条实现与多线程防阻塞详解
本文详细介绍如何使用 PySimpleGUI 库在 Python 中实现进度条。涵盖 one_line_progress_meter 快速用法及自定义窗口控件布局,重点解析耗时任务导致界面卡死的问题,并提供通过多线程与队列机制实现进度条非阻塞更新的完整代码示例。
PySimpleGUI 库在构建图形界面时,相比 tkinter 提供了更为便捷的封装体验。尽管两者使用场景各有侧重,但 PySimpleGUI 在简化任务进度模拟方面表现突出,适合快速开发。
安装
pip install PySimpleGUI
一、简单进度条使用
PySimpleGUI 提供了一行代码即可生成进度条的便捷控件 one_line_progress_meter。
import time
import PySimpleGUI as sg
if __name__ == '__main__':
sg.one_line_progress_meter('进度条标题',
10,
100,
'key1',
'内容')
# sg.one_line_progress_meter()
time.sleep(10)

该函数的基本参数依次对应:进度条显示标题、当前进度值、最大进度值、用于标识该进度条的 key(key 相同则指向同一进度条实例),以及后续可传入的多个非关键字参数。
sg.one_line_progress_meter('进度条标题',
10,
100,
'key1',
'内容1')
关于常用参数 orientation,由于函数支持 *args 可变参数,若需传入自定义参数,前面的基本参数必须以非关键字形式传递;若不传自定义参数则无此限制。orientation 参数用于指定进度条方向:'h' 代表横向,'v' 代表纵向(默认值)。
sg.one_line_progress_meter(title='进度条标题2',
current_value=20,
max_value=100,
key='key2',
orientation='h')

模拟进度条逐步填充过程
import time
import PySimpleGUI as sg
if __name__ == '__main__':
for i in range(1000):
time.sleep(0.02) # 模拟0.02s 完成了千分之一的任务
sg.one_line_progress_meter(
'进度条',
i+1,
1000,
'key',
'测试使用进度条',
orientation='h'
)

代码中的休眠时间可模拟任务执行耗时,每完成一步操作,进度条数值相应增加。
然而在实际运行中,若直接在主线程执行耗时任务,会导致进度条界面失去响应(如首图所示)。因此,常规做法是将耗时任务放入多线程执行,任务完成后通过特定机制通知主线程更新进度条状态。需注意,PySimpleGUI 的界面组件必须在主线程中运行,具体参考源文档说明。
虽然 one_line_progress_meter 调用简便,但其样式固定且不可控,界面中部分无关显示元素也无法隐藏。
附录:PySimpleGUI 弹窗功能示例
sg.popup('注意!')
sg.popup_ok('默认弹窗')
sg.popup_yes_no('带Yes和No按钮的弹窗')
sg.popup_cancel('带cancel按钮的弹窗')
sg.popup_ok_cancel('带OK和cancel按钮的弹窗')
sg.popup_error('带红色error按钮的弹窗')
sg.popup_auto_close('几秒后自动关闭的弹窗')
sg.popup_auto_close('10秒后自动关闭的弹窗', auto_close_duration=10)
二、进度条控件使用
通过常规方法展示进度条控件,需理解窗口布局与组件之间的关系。
import PySimpleGUI as sg
# 布局,是一个用户定义的二维列表。
# 第一维德元素分居不同的行上,第二维度上的元素们居于同一行,不同列上
# 此处定义的列表 由三部分组成 Text文件 ProgressBar进度条 Cancel取消按钮构成
# Text Progress等有各自的参数设置,如size等。此处不再赘述
layout = [[sg.Text('任务完成进度')],
[sg.ProgressBar(1000, orientation='h', size=(20, 20), key='progressbar')],
[sg.Cancel()]]
# window只需将自定义的布局加载出来即可 第一个参数是窗口标题。
window = sg.Window('机器人执行进度', layout)
# 根据key值获取到进度条
progress_bar = window['progressbar']
# window的read函数分为同步和异步,
# 不带timeout参数即为同步函数 一直等到手动点击按钮才会返回。
# 带timeout参数不为None的为异步函数,timeout时间内无时间或者点击了按钮都会产生结果。
# 异步方式不会阻塞后面的程序运行。
for i in range(1000): # 循环
event, values = window.read(timeout=10)
if event == 'Cancel' or event is None:
break
progress_bar.UpdateBar(i + 1)
window.close()

此处仍使用 for 循环驱动进度条填满。下方代码演示如何利用线程模拟任务完成过程。
三、模拟任务完成度 进度条
使用线程模拟任务进度。由于此处无真实业务逻辑,仍由 for 循环加休眠构成,但与直接调用不同,任务在子线程中执行,完成后需通知主线程更新进度条。
import random
import time
from queue import Empty
import PySimpleGUI as sg
import threading
import queue
# 布局,是一个用户定义的二维列表。
# 第一维德元素分居不同的行上,第二维度上的元素们居于同一行,不同列上
# 此处定义的列表 由三部分组成 Text文件 ProgressBar进度条 Cancel取消按钮构成
layout = [[sg.Text('任务完成进度')],
[sg.ProgressBar(100, orientation='h', size=(50, 20), key='progressbar')],
[sg.Cancel()]]
# window只需将自定义的布局加载出来即可 第一个参数是窗口标题。
window = sg.Window('机器人执行进度', layout)
# 根据key值获取到进度条
progress_bar = window['progressbar']
# 队列 后进先出
q = queue.Queue()
def task_1():
global q
for i in range(100):
# 因为要大于window.read设置超时时间100ms 保证读取时队列最多只有一个元素
time.sleep(random.random() + 0.1)
q.put(i+1) # 向队列中放入当前任务完成度
# 创建多线程 设置以保护模式启动,即主线程运行结束,子线程也停止运行
worker_task = threading.Thread(target=task_1)
worker_task.setDaemon(True)
worker_task.start()
while True: # 死循环不断读取队列中数据,直到读到100
# event 就是返回的事件
# 如点击Cancel后 event=Cancel
event, values = window.read(timeout=100)
if event == 'Cancel' or event is None:
# 点击取消按钮或者返回事件为 None
break
# 10ms 无操作算超时event会等于 __TIMEOUT__
# 其实不用判断
try:
# get是等待读取,直到读取到数据
# get_nowait 不等待,读取不到数据 就报异常
progress_value = q.get_nowait()
except Empty: # 没有读取到数据的话,继续window.read
continue
else: # 读取到数据
progress_bar.UpdateBar(progress_value)
if progress_value == 100: # 进度满跳出循环
break
window.close()

以上即为 Python 使用 PySimpleGUI 设置进度条的详细内容,更多关于 python PySimpleGUI 进度条的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













