首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在pySimpleGUI中运行复杂的代码?

在pySimpleGUI中运行复杂的代码?
EN

Stack Overflow用户
提问于 2020-07-03 00:01:07
回答 1查看 910关注 0票数 2

我尝试在GUI中运行一些代码,在GUI中,我在获得几个文本输入后运行一个函数。然而,我尝试运行的函数实际上非常复杂,所以当它运行时,它会使整个gui冻结10-15秒,然后才能继续运行。

我如何才能使它在我点击run按钮时,不会冻结整个GUI等待功能完成?

我确实知道有一种方法可以使函数线程化,但是我不知道如何实现它?

如果我能用一个例子来说明如何包装一个函数,让它成为一个线程函数,那就太好了。

下面的代码给出了我正在处理的问题的一个示例。

代码语言:javascript
运行
复制
import PySimpleGUI as sg
import time

def simple_gui():
    layout = [  [sg.T('try clicking "do something" and move the window')],
                [sg.Button('do something'), sg.Button('Exit')] ]
    w = sg.Window('test', layout)
    
    while True:
       events, values = w.read()
       if events == 'do something':
           # If you hit the button "do something":
           #    run a function that takes 30 seconds to complete.
           time.sleep(30)

       if events == sg.WIN_CLOSED or events == 'Exit':
            break
    
    w.close()
    
simple_gui()
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-07-04 04:23:34

有许多关于如何使用线程通过PySimpleGUI执行“长操作”的示例。您可以在http://Demos.PySimpleGUI.org上找到演示程序。至少有6个示例程序被标记为多线程示例。

有些还可以在Trinket上在线运行。这个示例展示了如何运行线程,然后等待它完成:

https://pysimplegui.trinket.io/demo-programs#/multi-threaded/multi-threaded-long-task-simple

这是你可以在那里找到的代码。

代码语言:javascript
运行
复制
#!/usr/bin/python3
import threading
import time
import PySimpleGUI as sg

"""
    DESIGN PATTERN - Multithreaded Long Tasks GUI using shared global variables

    Presents one method for running long-running operations in a PySimpleGUI environment.
    The PySimpleGUI code, and thus the underlying GUI framework, runs as the primary, main thread
    The "long work" is contained in the thread that is being started. Communicating is done (carefully) using global variables

    There are 2 ways "progress" is being reported to the user. 
    You can simulate the 2 different scenarios that happen with worker threads.
    1.  If a the amount of time is known ahead of time or the work can be broken down into countable units, then a progress bar is used.  
    2.  If a task is one long chunk of time that cannot be broken down into smaller units, then an animated GIF is shown that spins as
    long as the task is running.
"""

total = 100     # number of units that are used with the progress bar
message = ''    # used by thread to send back a message to the main thread
progress = 0    # current progress up to a maximum of "total"


def long_operation_thread(seconds):
    """
    A worker thread that communicates with the GUI through a global message variable
    This thread can block for as long as it wants and the GUI will not be affected
    :param seconds: (int) How long to sleep, the ultimate blocking call
    """

    global message, progress

    print('Thread started - will sleep for {} seconds'.format(seconds))
    for i in range(int(seconds * 10)):
        time.sleep(.1)  # sleep for a while
        progress += total / (seconds * 10)

    message = f'*** The thread says.... "I am finished" ***'

def the_gui():
    """
    Starts and executes the GUI
    Reads data from a global variable and displays
    Returns when the user exits / closes the window
    """
    global message, progress

    sg.theme('Light Brown 3')

    layout = [[sg.Text('Long task to perform example')],
              [sg.Output(size=(80, 12))],
              [sg.Text('Number of seconds your task will take'),
               sg.Input(key='-SECONDS-', size=(5, 1)),
               sg.Button('Do Long Task', bind_return_key=True),
               sg.CBox('ONE chunk, cannot break apart', key='-ONE CHUNK-')],
              [sg.Text('Work progress'), sg.ProgressBar(total, size=(20, 20), orientation='h', key='-PROG-')],
              [sg.Button('Click Me'), sg.Button('Exit')], ]

    window = sg.Window('Multithreaded Demonstration Window', layout)

    thread = None

    # --------------------- EVENT LOOP ---------------------
    while True:
        event, values = window.read(timeout=100)
        if event in (None, 'Exit'):
            break
        elif event.startswith('Do') and not thread:
            print('Thread Starting! Long work....sending value of {} seconds'.format(float(values['-SECONDS-'])))
            thread = threading.Thread(target=long_operation_thread, args=(float(values['-SECONDS-']),), daemon=True)
            thread.start()
        elif event == 'Click Me':
            print('Your GUI is alive and well')

        if thread:                                          # If thread is running
            if values['-ONE CHUNK-']:                       # If one big operation, show an animated GIF
                sg.popup_animated(sg.DEFAULT_BASE64_LOADING_GIF, background_color='white', transparent_color='white', time_between_frames=100)
            else:                                           # Not one big operation, so update a progress bar instead
                window['-PROG-'].update_bar(progress, total)
            thread.join(timeout=0)
            if not thread.is_alive():                       # the thread finished
                print(f'message = {message}')
                sg.popup_animated(None)                     # stop animination in case one is running
                thread, message, progress = None, '', 0     # reset variables for next run
                window['-PROG-'].update_bar(0,0)            # clear the progress bar

    window.close()


if __name__ == '__main__':
    the_gui()
    print('Exiting Program')
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62700493

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档