diff --git a/DemoPrograms/Demo_Threaded_Work.py b/DemoPrograms/Demo_Threaded_Work.py index bf08e4b0..475e374d 100644 --- a/DemoPrograms/Demo_Threaded_Work.py +++ b/DemoPrograms/Demo_Threaded_Work.py @@ -2,26 +2,47 @@ import queue import threading import time - import PySimpleGUI as sg -# Put your long-running code in here +""" + Demo on how to add a long-running item to your PySimpleGUI Event Loop + If you want to do something that takes a long time, and you do it in the + main event loop, you'll quickly begin to see messages from windows that your + program has hung, asking if you want to kill it. + + The problem is not that your problem is hung, the problem is that you are + not calling Read or Refresh often enough. + + One way through this, shown here, is to put your long work into a thread that + is spun off, allowed to work, and then gets back to the GUI when it's done working + on that task. + + If you have multiple long tasks to run, then you'll want a more sophisticated + format to your messages going back to the GUI so you'll know which task finished +""" + + +# --------------------------------------- +# Put your long-running code in here # +# --------------------------------------- def worker_thread(thread_name, gui_queue): print('Starting thread - {} '.format(thread_name)) # this is our "long running function call" time.sleep(5) # sleep for a while + print('Ending thread - {} '.format(thread_name)) # at the end of the work, before exiting, send a message back to the GUI indicating end + # in this case, we're using a simple string gui_queue.put('{} - done'.format(thread_name)) # put a message into queue for GUI -###### ## ## #### +######## ## ## #### ## ## ## ## ## ## ## ## ## ## #### ## ## ## ## ## ## ## ## ## ## ## ## ## -###### ####### #### +######## ######### #### def the_gui(gui_queue): @@ -32,29 +53,27 @@ def the_gui(gui_queue): window = sg.Window('Multithreaded Window').Layout(layout) # --------------------- EVENT LOOP --------------------- - message = None count = 0 while True: event, values = window.Read(timeout=100) # wait for up to 100 ms for a GUI event if event is None or event == 'Exit': break - if event == 'Go': + if event == 'Go': # clicking "Go" starts a long running work item by starting thread window.Element('_OUTPUT_').Update('Starting long work %s'%count) - # simulate STARTING long run by starting a thread + # STARTING long run by starting a thread threading.Thread(target=worker_thread, args=('Thread %s'%count, gui_queue,), daemon=True).start() count += 1 - # --------------- Loop through all messages coming in from threads --------------- - try: # see if something has been posted to Queue - message = gui_queue.get_nowait() - except queue.Empty: # get_nowait() will get exception when Queue is empty - pass # nothing in queue so do nothing + # --------------- Read next message coming in from threads --------------- + try: + message = gui_queue.get_nowait() # see if something has been posted to Queue + except queue.Empty: # get_nowait() will get exception when Queue is empty + message = None # nothing in queue so do nothing # if message received from queue, display the message in the Window if message is not None: # this is the place you would execute code at ENDING of long running task window.Element('_OUTPUT_').Update(message) window.Refresh() # do a refresh because could be showing multiple messages before next Read - message = None # if user exits the window, then close the window and exit the GUI func window.Close()