pysimplegui之使用多线程,避免程序卡死(Pysimplegui uses multithreading to avoid program jamming)

这个问题我也遇到过,就是还需要一个while循环的时候,放到gui本身循环会卡死,这时候就需要启动多线程

需要“长时间”的操作

如果您是 Windows 用户,您会在其标题栏中看到窗口显示“未响应”,然后很快会出现一个 Windows 弹出窗口,指出“您的程序已停止响应”。好吧,如果您愿意,您也可以使该消息和弹出窗口出现!您需要做的就是在您的事件循环中执行一个花费“太长”(即几秒钟)的操作。

你有几个选择来处理这个问题。如果您的操作可以分解成更小的部分,那么您可以偶尔调用以避免出现此消息。例如,如果您正在运行一个循环,请将该调用与您的其他工作一起放入。这将使 GUI 保持快乐,Window 不会抱怨。

Window.Refresh()

另一方面,如果您的操作不受您的控制,或者您无法添加调用,那么您可以使用的下一个选项是将您的长操作移动到一个线程中。

Refresh

“老路”

有几个演示程序可供您查看如何执行此操作。你基本上把你的工作放到一个线程中。当线程完成时,它通过队列发送消息来告诉 GUI。事件循环将运行一个计时器,该计时器设置为一个值,该值表示您希望您的 GUI 对工作完成的“响应”程度。

“新方式”—— Window.write_event_value

Window.write_event_value

这个截至 2020 年 7 月目前仅在 tkinter 端口中可用的新功能令人兴奋,它代表了在 PySimpleGUI 中处理多线程的未来方式(或者希望如此)。

以前,使用队列,您的事件循环将轮询来自线程的传入消息。

现在,线程可以直接将事件注入到 Window 中,以便它显示在调用中。这允许您的事件循环“挂起”,等待正常的窗口事件以及线程生成的事件。

window.read()

您可以在此演示中看到此新功能的实际效果:Demo_Multithreaded_Write_Event_Value.py

这是您的检查和教育计划。不再轮询线程事件真是太好了。

import threading
import time
import PySimpleGUI as sg

"""
    Threaded Demo - Uses Window.write_event_value communications

    Requires PySimpleGUI.py version 4.25.0 and later

    This is a really important demo  to understand if you're going to be using multithreading in PySimpleGUI.

    Older mechanisms for multi-threading in PySimpleGUI relied on polling of a queue. The management of a communications
    queue is now performed internally to PySimpleGUI.

    The importance of using the new window.write_event_value call cannot be emphasized enough.  It will hav a HUGE impact, in
    a positive way, on your code to move to this mechanism as your code will simply "pend" waiting for an event rather than polling.

    Copyright 2020 PySimpleGUI.org
"""

THREAD_EVENT = '-THREAD-'

cp = sg.cprint

def the_thread(window):
    """
    The thread that communicates with the application through the window's events.

    Once a second wakes and sends a new event and associated value to the window
    """
    i = 0
    while True:
        time.sleep(1)
        window.write_event_value('-THREAD-', (threading.current_thread().name, i))      # Data sent is a tuple of thread name and counter
        cp('This is cheating from the thread', c='white on green')
        i += 1

def main():
    """
    The demo will display in the multiline info about the event and values dictionary as it is being
    returned from window.read()
    Every time "Start" is clicked a new thread is started
    Try clicking "Dummy" to see that the window is active while the thread stuff is happening in the background
    """

    layout = [  [sg.Text('Output Area - cprint\'s route to here', font='Any 15')],
                [sg.Multiline(size=(65,20), key='-ML-', autoscroll=True, reroute_stdout=True, write_only=True, reroute_cprint=True)],
                [sg.T('Input so you can see data in your dictionary')],
                [sg.Input(key='-IN-', size=(30,1))],
                [sg.B('Start A Thread'), sg.B('Dummy'), sg.Button('Exit')]  ]

    window = sg.Window('Window Title', layout, finalize=True)

    while True:             # Event Loop
        event, values = window.read()
        cp(event, values)
        if event == sg.WIN_CLOSED or event == 'Exit':
            break
        if event.startswith('Start'):
            threading.Thread(target=the_thread, args=(window,), daemon=True).start()
        if event == THREAD_EVENT:
            cp(f'Data from the thread ', colors='white on purple', end='')
            cp(f'{values[THREAD_EVENT]}', colors='white on red')
    window.close()

if __name__ == '__main__':
    main()

多线程程序

在讨论多线程主题时,准备了另一个演示,展示了如何在程序中运行多个线程,这些线程都与事件循环通信,以便在 GUI 窗口中显示某些内容。回想一下,对于 PySimpleGUI(至少是 tkinter 端口),您不能在主程序线程以外的线程中进行 PySimpleGUI 调用。

这些线程程序的关键是从线程到事件循环的通信。为这些演示选择的机制使用 Python 内置模块。事件循环轮询这些队列以查看是否从要显示的线程之一发送了某些内容。

queue

您会发现显示多个线程与单个 GUI 通信的演示被称为:

Demo_Multithreaded_Queued.py

对于普通的 PySimpleGUI(基于 tkinter)再次发出警告- 您的 GUI 绝不能作为除主程序线程之外的任何东西运行,并且没有线程可以直接调用 PySimpleGUI 调用

————————

I have also encountered this problem. When a while loop is needed, the loop will get stuck in the GUI itself. At this time, you need to start multithreading

Long time operation required

If you are a Windows user, you will see the window display “not responding” in its title bar, and then a Windows pop-up window will appear soon, indicating that “your program has stopped responding”. Well, you can also make the message and pop-up window appear if you like! All you need to do is perform an operation that takes “too long” (that is, a few seconds) in your event loop.

You have several options to deal with this problem. If your operation can be broken down into smaller parts, you can call it occasionally to avoid this message. For example, if you are running a loop, put the call in with your other work. This will keep the GUI happy and window won’t complain.

Window.Refresh()

On the other hand, if your operation is not under your control, or you cannot add a call, the next option you can use is to move your long operation to a thread.

Refresh

“Old road”

There are several demo programs for you to see how to do this. You basically put your work in one thread. When the thread completes, it sends a message through the queue to tell the GUI. The event loop runs a timer that is set to a value that indicates how “responsive” you want your GUI to be to work completion.

“新方式”—— Window.write_event_value

Window.write_event_value

This exciting new feature, currently available only on the Tkinter port as of July 2020, represents the future (or hopefully) way to handle multithreading in pysimplegui.

Previously, using queues, your event loop would < strong > poll < / strong > incoming messages from threads.

The thread can now inject the event directly into window so that it appears in the call. This allows your event loop to “hang” and wait for normal window events and thread generated events.

window.read()

You can see the actual effect of this new feature in this demonstration: demo_ Multithreaded_ Write_ Event_ Value. py

This is your inspection and education plan. It’s great not to poll thread events anymore.

import threading
import time
import PySimpleGUI as sg

"""
    Threaded Demo - Uses Window.write_event_value communications

    Requires PySimpleGUI.py version 4.25.0 and later

    This is a really important demo  to understand if you're going to be using multithreading in PySimpleGUI.

    Older mechanisms for multi-threading in PySimpleGUI relied on polling of a queue. The management of a communications
    queue is now performed internally to PySimpleGUI.

    The importance of using the new window.write_event_value call cannot be emphasized enough.  It will hav a HUGE impact, in
    a positive way, on your code to move to this mechanism as your code will simply "pend" waiting for an event rather than polling.

    Copyright 2020 PySimpleGUI.org
"""

THREAD_EVENT = '-THREAD-'

cp = sg.cprint

def the_thread(window):
    """
    The thread that communicates with the application through the window's events.

    Once a second wakes and sends a new event and associated value to the window
    """
    i = 0
    while True:
        time.sleep(1)
        window.write_event_value('-THREAD-', (threading.current_thread().name, i))      # Data sent is a tuple of thread name and counter
        cp('This is cheating from the thread', c='white on green')
        i += 1

def main():
    """
    The demo will display in the multiline info about the event and values dictionary as it is being
    returned from window.read()
    Every time "Start" is clicked a new thread is started
    Try clicking "Dummy" to see that the window is active while the thread stuff is happening in the background
    """

    layout = [  [sg.Text('Output Area - cprint\'s route to here', font='Any 15')],
                [sg.Multiline(size=(65,20), key='-ML-', autoscroll=True, reroute_stdout=True, write_only=True, reroute_cprint=True)],
                [sg.T('Input so you can see data in your dictionary')],
                [sg.Input(key='-IN-', size=(30,1))],
                [sg.B('Start A Thread'), sg.B('Dummy'), sg.Button('Exit')]  ]

    window = sg.Window('Window Title', layout, finalize=True)

    while True:             # Event Loop
        event, values = window.read()
        cp(event, values)
        if event == sg.WIN_CLOSED or event == 'Exit':
            break
        if event.startswith('Start'):
            threading.Thread(target=the_thread, args=(window,), daemon=True).start()
        if event == THREAD_EVENT:
            cp(f'Data from the thread ', colors='white on purple', end='')
            cp(f'{values[THREAD_EVENT]}', colors='white on red')
    window.close()

if __name__ == '__main__':
    main()

Multithreaded program

When discussing the topic of multithreading, another demonstration was prepared to show how to run multiple threads in a program, which communicate with event loops to display something in Gui windows. Recall that for pysimplegui (at least the Tkinter port), you cannot make pysimplegui calls in a thread other than the main program thread.

The key to these threaded programs is the communication from thread to event loop. The mechanism chosen for these demonstrations uses Python’s built-in modules. Event loops poll these queues to see if something was sent from one of the threads to be displayed.

queue

You will find that a presentation that shows multiple threads communicating with a single GUI is called:

Demo_Multithreaded_Queued.py

For ordinary pysimplegui (based on Tkinter), issue a < strong > warning again – your GUI must not run as anything other than the main program thread, and no thread can directly call pysimplegui to call < / strong >