Question
Windows 10 (20H2)
3.6
Ports = tkinter
PySimpleGUI Version: 4.32.1
tkinter version: 8.6.6
3 years - Python programming experience
3 years - Programming experience overall
No - Have used another Python GUI Framework (tkinter, Qt, etc) previously (yes/no is fine)?
Can a thread (not main) act to return an event trigger to the GUI? According to the documentation, this might not be possible.
My workflow for threading is this:
I have an event in the loop that checks if the thread is completed (using is_alive()), but this is only triggered when a user selects an event (in this case, clicks a button).
I've consulted the documentation, which states the following: "no threads can directly call PySimpleGUI calls,โ as well as this documentation on multi-threading. I'm taking this to mean my desired behavior actually isn't possible if this is the case, but I could be misunderstanding.
I consulted the Window.write_event_value() demo, but I don't think it's quite what I'm looking for. Here's a gif of my program now:

import PySimpleGUI as sg
if event_simple == "_EXPORT_EAD_":
window_simple[f'{"_EXPORT_EAD_"}'].update(disabled=True)
ead_thread = threading.Thread(target=get_eads, args=(input_ids, defaults, cleanup_options, repositories, client, values_simple,))
ead_thread.start()
if not ead_thread.is_alive():
window_simple[f'{"_EXPORT_EAD_"}'].update(disabled=False) # This is only triggered when a user clicks a button - I want it to update when ead_thread is completed.
Not read full of your issue exactly, but it seems not correct about threading as you mentioned.
Demo_Multithreaded_Write_Event_Value.py
write_event_valueAdds a key & value tuple to the queue that is used by threads to communicate with the window
Modified code per above example, here write_event_value called in thread.
from time import sleep
import threading
import PySimpleGUI as sg
THREAD_EVENT = '-THREAD-'
def the_thread(window):
sleep(2)
window.write_event_value('-THREAD-', (threading.current_thread().name,))
def main():
layout = [
[sg.Button('Start A Thread')],
[sg.Text("", size=(50, 1), key='Status')]]
window = sg.Window('Window Title', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
if event == 'Start A Thread':
threading.Thread(target=the_thread, args=(window,), daemon=True).start()
window['Start A Thread'].update(disabled=True)
window['Status'].update("Button disabled now, will be enabled after 2 seconds")
if event == THREAD_EVENT:
window['Start A Thread'].update(disabled=False)
window['Status'].update("")
window.close()
if __name__ == '__main__':
main()
Jason's posted the right way for a thread to communicate with the event loop.
The primary documentation needs to be updated... thanks for the reminder.
The Cookbook has a section devoted to Multi-threading.
https://pysimplegui.readthedocs.io/en/latest/cookbook/#recipe-long-operations-multi-threading
In it you'll find a description of the single call that's available to threads, window.write_event_value(). You may "get away" (i.e. your program won't immediately crash) with making some calls, some of the time, but you'll most likely eventually get caught.
There are also numerous demo programs that use write_event_value. I count 6 of them at the moment. They all start with "Demo_Multithreaded_".
I'll update the primary documentation so that the section on multi-threading discusses the write_event_value call.
I think the question has been answered so closing this Issue. Feel free to reply if you still don't understand.
Thank you @jason990420 and @PySimpleGUI ! I didn't fully understand how write_event_value works, but now it makes more sense. It's essentially doing exactly what I want in writing an event and value back to the GUI - back when I wrote the GUI before July 2020, this wasn't a feature yet.
I'm still confused as to how it works its magic (this bit here: '-THREAD-', (threading.current_thread().name,)), but I tested it in my code and it works as the cookbook and examples show.
The write function takes 2 parameters. The first is the event that will be returned to your window.read() function. The second parameter is the value that will be in your values dictionary for that event. Think of it like an Input element with events enabled. The read will return the "key", which is the event parameter. The values dictionary will have the value values[event] set to whatever you specify as the second parameter.
One way to learn all this stuff is to put a print statement after your window.read() call. You'll find in almost every program I write there's a print(event, values) statement after my window.read() call. This is because those 2 variables are THE most important variables in your event loop. They hold everything that you'll be working with.
That makes sense, thank you! I'll start putting a print statement for event, values after window.read() to make better sense of it all.