【Python】pysimplegui主动事件(多线程执行耗时任务解决主线程卡死问题)

1.说明

PySimpleGui是一个免费开源的Python GUI库,用起来比Tkinter、PyQt5等库更简单,所以可以用来快速开发GUI程序,高效便捷。关于PySimpleGUI的基本使用,可以参考之前的文章,【Python】Python图形化界面库PySimpleGUI的简单使用

默认情况下我们习惯在主线程更新UI,但是,一旦遇到耗时任务,界面就会卡住,甚至进入假死状态,Win系统会提示你“程序无响应”,这明显对用户很不友好,所以我们要考虑把耗时任务放在子线程执行,主线程就只管更新UI,保证主线程不会卡死

2.主动发出事件

开启多线程的方式我们都学过,但问题是,在子线程里执行任务就变得不好与主线程交互了,比如说,想要把子线程里的执行进度更新到UI,这就需要子线程与主程序进行交互,即主线程需要拿到子线程的数据。

之前我们处理的事件都是通过点击UI等方式发出的,即由用户发出,实际上,Window对象也可以主动发出事件,只要调用一下Window对象的write_event_value()方法就行

import PySimpleGUI as sg

layout = [
    [sg.Button('开始'), sg.Button('退出')]
]
window = sg.Window('新窗口', layout)

while True:
    event, values = window.read()
    print(f"event: {
      
      event}, values:{
      
      values}")
    if event == sg.WIN_CLOSED or event == '退出' or event == "主动事件":
        break
    else:
        # 主动发出事件,事件名是“主动事件”,事件值是“主动发出的事件”
        window.write_event_value("主动事件", "主动发出的事件")

window.close()

3.在子程更新UI

知道了Window对象有write_event_value()方法之后,我们就可以在子线程与主线程交互了,即只要在子线程里调用Window对象的write_event_value()方法,主线程监听到子线程发出的事件就更新UI,演示代码如下

import PySimpleGUI as sg

import time
import threading


def long_time_work(window):
    for i in range(10):
        time.sleep(1)
        window.write_event_value('任务进度', i)
    window.write_event_value('任务结束', '')


layout = [
    [sg.Output(size=(60, 10))],
    [sg.Button('开始'), sg.Button('退出')]
]

window = sg.Window('耗时任务演示', layout)

while True:
    event, values = window.read()
    if event == sg.WIN_CLOSED or event == '退出':
        break
    if event == '开始':
        print('点击了“开始”按钮,即将调用耗时函数')
        threading.Thread(target=long_time_work, args=(window,), daemon=True).start()
        print('已调用耗时函数')
    elif event == '任务结束':
        print('任务已结束')
    else:
        print(f'-- {
      
      event}: {
      
      values["任务进度"]}')
window.close()

上面的代码中使用了sg.Output元素,该元素继承自Multiline,它会把标准输出重定向到Output里,即打印东西不会在控制台显示而是会在Output界面演示

猜你喜欢

转载自blog.csdn.net/qq_39147299/article/details/128641178