pysimplegui uses multithreading to avoid program jamming

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 use Window Refresh() is called 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.

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

"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.

"New way" -- 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, with queues, your event loop would poll for incoming messages from threads.

Now, the thread can inject the event directly into the Window so that it can be displayed in the Window In the read() call. This allows your event loop to "hang" and wait for normal Window events and thread generated events.

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 queue module. Event loops poll these queues to see if something was sent from one of the threads to be displayed.

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

Demo_Multithreaded_Queued.py

Warning again for ordinary PySimpleGUI (tkinter based) - your GUI must not run as anything other than the main program thread, and no thread can call PySimpleGUI directly

Keywords: Python

Added by dcooper on Sat, 15 Jan 2022 20:31:09 +0200