Skip to content

Commit 54aff59

Browse files
Merge pull request PySimpleGUI#1412 from PySimpleGUI/pulls_go_here
Better commenting and message passing with "Work ID" checks
2 parents 3f6938b + 6acdac5 commit 54aff59

File tree

1 file changed

+39
-68
lines changed

1 file changed

+39
-68
lines changed

DemoPrograms/Demo_Threaded_Work.py

Lines changed: 39 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
import PySimpleGUI as sg
66

77
"""
8+
You want to look for 3 points in this code, marked with comment "LOCATION X".
9+
1. Where you put your call that takes a long time
10+
2. Where the trigger to make the call takes place in the event loop
11+
3. Where the completion of the call is indicated in the event loop
12+
813
Demo on how to add a long-running item to your PySimpleGUI Event Loop
914
If you want to do something that takes a long time, and you do it in the
1015
main event loop, you'll quickly begin to see messages from windows that your
@@ -17,109 +22,75 @@
1722
is spun off, allowed to work, and then gets back to the GUI when it's done working
1823
on that task.
1924
20-
If you have multiple long tasks to run, then you'll want a more sophisticated
21-
format to your messages going back to the GUI so you'll know which task finished
25+
Every time you start up one of these long-running functions, you'll give it an "ID".
26+
When the function completes, it will send to the GUI Event Loop a message with
27+
the format:
28+
work_id ::: done
29+
This makes it easy to parse out your original work ID
30+
31+
You can hard code these IDs to make your code more readable. For example, maybe
32+
you have a function named "update_user_list()". You can call the work ID "user list".
33+
Then check for the message coming back later from the work task to see if it starts
34+
with "user list". If so, then that long-running task is over.
2235
23-
You want to look for 3 points in this code.
24-
1. Where you put your call that takes a long time
25-
2. Where the trigger to make the call takes place in the event loop
26-
3. Where the completion of the call is indicated in the event loop
2736
"""
2837

29-
# Put your....
30-
31-
###### ######## ## ##
32-
## ## ## ## ## ##
33-
## ## ## ## ##
34-
## ######## ## ##
35-
## ## ## ##
36-
## ## ## ## ##
37-
###### ## #######
38-
39-
#### ## ## ######## ######## ## ## ###### #### ## ## ########
40-
## ### ## ## ## ### ## ## ## ## ## ## ##
41-
## #### ## ## ## #### ## ## ## ## ## ##
42-
## ## ## ## ## ###### ## ## ## ###### ## ## ## ######
43-
## ## #### ## ## ## #### ## ## ## ## ##
44-
## ## ### ## ## ## ### ## ## ## ## ## ##
45-
#### ## ## ## ######## ## ## ###### #### ### ########
46-
47-
###### ####### ######## ########
48-
## ## ## ## ## ## ##
49-
## ## ## ## ## ##
50-
## ## ## ## ## ######
51-
## ## ## ## ## ##
52-
## ## ## ## ## ## ##
53-
###### ####### ######## ########
54-
55-
# Here in this thread
56-
57-
def worker_thread(thread_name, gui_queue):
58-
print('Starting thread - {} '.format(thread_name))
38+
# ############################# User callable CPU intensive code #############################
39+
# Put your long running code inside this "wrapper"
40+
# NEVER make calls to PySimpleGUI from this thread (or any thread)!
41+
# Create one of these functions for EVERY long-running call you want to make
42+
def long_function_wrapper(work_id, gui_queue):
43+
print('Thread starting - {} '.format(work_id))
5944
# LOCATION 1
6045
# this is our "long running function call"
6146
time.sleep(5) # sleep for a while
62-
print('Ending thread - {} '.format(thread_name))
63-
47+
print('Thread Ending - {} '.format(work_id))
6448
# at the end of the work, before exiting, send a message back to the GUI indicating end
65-
# in this case, we're using a simple string
66-
gui_queue.put('{} - done'.format(thread_name)) # put a message into queue for GUI
67-
49+
gui_queue.put('{} ::: done'.format(work_id))
6850

69-
######## ## ## ####
70-
## ## ## ## ##
71-
## ## ## ##
72-
## #### ## ## ##
73-
## ## ## ## ##
74-
## ## ## ## ##
75-
######## ######### ####
7651

52+
############################# Begin GUI code #############################
7753
def the_gui():
78-
gui_queue = queue.Queue() # queue used to communicate between the gui and the threads
54+
gui_queue = queue.Queue() # queue used to communicate between the gui and long-running code
7955

8056
layout = [[sg.Text('Multithreaded Work Example')],
57+
[sg.Text('Click Go to start a long-running function call')],
8158
[sg.Text('', size=(25, 1), key='_OUTPUT_')],
82-
# [sg.Output(size=(40,6))],
59+
[sg.Text('', size=(25, 1), key='_OUTPUT2_')],
8360
[sg.Button('Go'), sg.Button('Popup'), sg.Button('Exit')], ]
8461

8562
window = sg.Window('Multithreaded Window').Layout(layout)
8663
# --------------------- EVENT LOOP ---------------------
87-
count = 0
64+
work_id = 0
8865
while True:
8966
event, values = window.Read(timeout=100) # wait for up to 100 ms for a GUI event
9067
if event is None or event == 'Exit':
9168
break
9269
if event == 'Go': # clicking "Go" starts a long running work item by starting thread
93-
window.Element('_OUTPUT_').Update('Starting long work %s'%count)
70+
window.Element('_OUTPUT_').Update('Starting long work %s'%work_id)
9471
# LOCATION 2
9572
# STARTING long run by starting a thread
96-
threading.Thread(target=worker_thread, args=('Thread %s'%count, gui_queue,), daemon=True).start()
97-
count += 1
73+
threading.Thread(target=long_function_wrapper, args=(work_id, gui_queue,), daemon=True).start()
74+
work_id += 1
9875
# --------------- Read next message coming in from threads ---------------
9976
try:
100-
message = gui_queue.get_nowait() # see if something has been posted to Queue
101-
except queue.Empty: # get_nowait() will get exception when Queue is empty
102-
message = None # nothing in queue so do nothing
77+
message = gui_queue.get_nowait() # see if something has been posted to Queue
78+
except queue.Empty: # get_nowait() will get exception when Queue is empty
79+
message = None # nothing in queue so do nothing
10380

104-
# if message received from queue, display the message in the Window
81+
# if message received from queue, then some work was completed
10582
if message is not None:
10683
# LOCATION 3
10784
# this is the place you would execute code at ENDING of long running task
108-
window.Element('_OUTPUT_').Update(message)
109-
85+
# You can check the completed_work_id variable to see exactly which long-running function completed
86+
completed_work_id = message[:message.index(' :::')]
87+
window.Element('_OUTPUT2_').Update('Complete Work ID "{}"'.format(completed_work_id))
11088
if event == 'Popup':
11189
sg.Popup('This is a popup showing that the GUI is running')
11290
# if user exits the window, then close the window and exit the GUI func
11391
window.Close()
11492

115-
116-
## ## ### #### ## ##
117-
### ### ## ## ## ### ##
118-
#### #### ## ## ## #### ##
119-
## ### ## ## ## ## ## ## ##
120-
## ## ######### ## ## ####
121-
## ## ## ## ## ## ###
122-
## ## ## ## #### ## ##
93+
############################# Main #############################
12394

12495
if __name__ == '__main__':
12596
the_gui()

0 commit comments

Comments
 (0)