Better coments. Uses "Work ID" concept

This commit is contained in:
MikeTheWatchGuy 2019-05-15 08:58:03 -04:00
parent 8c20619b2a
commit 0072cef950
1 changed files with 40 additions and 69 deletions

View File

@ -5,6 +5,11 @@ import time
import PySimpleGUI as sg
"""
You want to look for 3 points in this code, marked with comment "LOCATION X".
1. Where you put your call that takes a long time
2. Where the trigger to make the call takes place in the event loop
3. Where the completion of the call is indicated in the event loop
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
@ -17,109 +22,75 @@ import PySimpleGUI as sg
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
Every time you start up one of these long-running functions, you'll give it an "ID".
When the function completes, it will send to the GUI Event Loop a message with
the format:
work_id ::: done
This makes it easy to parse out your original work ID
You can hard code these IDs to make your code more readable. For example, maybe
you have a function named "update_user_list()". You can call the work ID "user list".
Then check for the message coming back later from the work task to see if it starts
with "user list". If so, then that long-running task is over.
You want to look for 3 points in this code.
1. Where you put your call that takes a long time
2. Where the trigger to make the call takes place in the event loop
3. Where the completion of the call is indicated in the event loop
"""
# Put your....
###### ######## ## ##
## ## ## ## ## ##
## ## ## ## ##
## ######## ## ##
## ## ## ##
## ## ## ## ##
###### ## #######
#### ## ## ######## ######## ## ## ###### #### ## ## ########
## ### ## ## ## ### ## ## ## ## ## ## ##
## #### ## ## ## #### ## ## ## ## ## ##
## ## ## ## ## ###### ## ## ## ###### ## ## ## ######
## ## #### ## ## ## #### ## ## ## ## ##
## ## ### ## ## ## ### ## ## ## ## ## ##
#### ## ## ## ######## ## ## ###### #### ### ########
###### ####### ######## ########
## ## ## ## ## ## ##
## ## ## ## ## ##
## ## ## ## ## ######
## ## ## ## ## ##
## ## ## ## ## ## ##
###### ####### ######## ########
# Here in this thread
def worker_thread(thread_name, gui_queue):
print('Starting thread - {} '.format(thread_name))
# ############################# User callable CPU intensive code #############################
# Put your long running code inside this "wrapper"
# NEVER make calls to PySimpleGUI from this thread (or any thread)!
# Create one of these functions for EVERY long-running call you want to make
def long_function_wrapper(work_id, gui_queue):
# LOCATION 1
# this is our "long running function call"
time.sleep(5) # sleep for a while
print('Ending thread - {} '.format(thread_name))
time.sleep(5) # sleep for a while as a simulation of a long-running computation
# 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
gui_queue.put('{} ::: done'.format(work_id))
# at this point, the thread exits
return
######## ## ## ####
## ## ## ## ##
## ## ## ##
## #### ## ## ##
## ## ## ## ##
## ## ## ## ##
######## ######### ####
############################# Begin GUI code #############################
def the_gui():
gui_queue = queue.Queue() # queue used to communicate between the gui and the threads
gui_queue = queue.Queue() # queue used to communicate between the gui and long-running code
layout = [[sg.Text('Multithreaded Work Example')],
[sg.Text('Click Go to start a long-running function call')],
[sg.Text('', size=(25, 1), key='_OUTPUT_')],
# [sg.Output(size=(40,6))],
[sg.Text('', size=(25, 1), key='_OUTPUT2_')],
[sg.Button('Go'), sg.Button('Popup'), sg.Button('Exit')], ]
window = sg.Window('Multithreaded Window').Layout(layout)
# --------------------- EVENT LOOP ---------------------
count = 0
work_id = 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': # clicking "Go" starts a long running work item by starting thread
window.Element('_OUTPUT_').Update('Starting long work %s'%count)
window.Element('_OUTPUT_').Update('Starting long work %s'%work_id)
# LOCATION 2
# STARTING long run by starting a thread
threading.Thread(target=worker_thread, args=('Thread %s'%count, gui_queue,), daemon=True).start()
count += 1
threading.Thread(target=long_function_wrapper, args=(work_id, gui_queue,), daemon=True).start()
work_id += 1
# --------------- 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
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 received from queue, then some work was completed
if message is not None:
# LOCATION 3
# this is the place you would execute code at ENDING of long running task
window.Element('_OUTPUT_').Update(message)
# You can check the completed_work_id variable to see exactly which long-running function completed
completed_work_id = message[:message.index(' :::')]
window.Element('_OUTPUT2_').Update('Complete Work ID "{}"'.format(completed_work_id))
if event == 'Popup':
sg.Popup('This is a popup showing that the GUI is running')
# if user exits the window, then close the window and exit the GUI func
window.Close()
## ## ### #### ## ##
### ### ## ## ## ### ##
#### #### ## ## ## #### ##
## ### ## ## ## ## ## ## ##
## ## ######### ## ## ####
## ## ## ## ## ## ###
## ## ## ## #### ## ##
############################# Main #############################
if __name__ == '__main__':
the_gui()