2019-05-14 18:23:30 +00:00
|
|
|
#!/usr/bin/python3
|
|
|
|
import threading
|
|
|
|
import time
|
|
|
|
import PySimpleGUI as sg
|
|
|
|
|
2019-05-14 21:40:30 +00:00
|
|
|
"""
|
2019-05-15 12:58:03 +00:00
|
|
|
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
|
|
|
|
|
2019-05-14 21:40:30 +00:00
|
|
|
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.
|
|
|
|
|
2019-05-15 12:58:03 +00:00
|
|
|
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.
|
2019-05-15 00:59:12 +00:00
|
|
|
|
2019-05-14 21:40:30 +00:00
|
|
|
"""
|
|
|
|
|
2019-05-15 12:58:03 +00:00
|
|
|
# ############################# 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
|
2019-10-23 20:10:03 +00:00
|
|
|
|
|
|
|
|
2020-07-18 17:42:32 +00:00
|
|
|
def long_function_wrapper(work_id, window):
|
2019-05-15 00:59:12 +00:00
|
|
|
# LOCATION 1
|
2019-05-14 18:23:30 +00:00
|
|
|
# this is our "long running function call"
|
2019-10-23 20:10:03 +00:00
|
|
|
# sleep for a while as a simulation of a long-running computation
|
|
|
|
time.sleep(5)
|
2019-05-14 18:23:30 +00:00
|
|
|
# at the end of the work, before exiting, send a message back to the GUI indicating end
|
2020-07-18 17:42:32 +00:00
|
|
|
window.write_event_value('-THREAD DONE-', work_id)
|
2019-05-15 12:58:03 +00:00
|
|
|
# at this point, the thread exits
|
|
|
|
return
|
2019-05-14 18:23:30 +00:00
|
|
|
|
2019-05-19 14:33:58 +00:00
|
|
|
|
2019-05-15 12:58:03 +00:00
|
|
|
############################# Begin GUI code #############################
|
2019-05-15 00:59:12 +00:00
|
|
|
def the_gui():
|
2019-12-24 23:52:47 +00:00
|
|
|
sg.theme('Light Brown 3')
|
2019-11-25 06:15:47 +00:00
|
|
|
|
2019-05-14 18:23:30 +00:00
|
|
|
|
|
|
|
layout = [[sg.Text('Multithreaded Work Example')],
|
2019-05-15 12:58:03 +00:00
|
|
|
[sg.Text('Click Go to start a long-running function call')],
|
2019-11-25 06:15:47 +00:00
|
|
|
[sg.Text(size=(25, 1), key='-OUTPUT-')],
|
|
|
|
[sg.Text(size=(25, 1), key='-OUTPUT2-')],
|
|
|
|
[sg.Text('⚫', text_color='blue', key=i, pad=(0,0), font='Default 14') for i in range(20)],
|
2019-08-29 19:57:14 +00:00
|
|
|
[sg.Button('Go'), sg.Button('Popup'), sg.Button('Exit')], ]
|
2019-05-14 18:23:30 +00:00
|
|
|
|
2019-10-23 20:10:03 +00:00
|
|
|
window = sg.Window('Multithreaded Window', layout)
|
2019-05-14 18:23:30 +00:00
|
|
|
# --------------------- EVENT LOOP ---------------------
|
2019-05-15 12:58:03 +00:00
|
|
|
work_id = 0
|
2019-05-14 18:23:30 +00:00
|
|
|
while True:
|
2019-10-23 20:10:03 +00:00
|
|
|
# wait for up to 100 ms for a GUI event
|
2020-07-18 17:42:32 +00:00
|
|
|
event, values = window.read()
|
2020-05-07 10:22:59 +00:00
|
|
|
if event in (sg.WIN_CLOSED, 'Exit'):
|
2019-05-14 18:23:30 +00:00
|
|
|
break
|
2019-05-14 21:40:30 +00:00
|
|
|
if event == 'Go': # clicking "Go" starts a long running work item by starting thread
|
2019-10-23 20:10:03 +00:00
|
|
|
window['-OUTPUT-'].update('Starting long work %s' % work_id)
|
2019-11-25 06:15:47 +00:00
|
|
|
window[work_id].update(text_color='red')
|
2019-05-15 00:59:12 +00:00
|
|
|
# LOCATION 2
|
2019-05-14 21:40:30 +00:00
|
|
|
# STARTING long run by starting a thread
|
2019-10-23 20:10:03 +00:00
|
|
|
thread_id = threading.Thread(
|
|
|
|
target=long_function_wrapper,
|
2020-07-18 17:42:32 +00:00
|
|
|
args=(work_id, window,),
|
2019-10-23 20:10:03 +00:00
|
|
|
daemon=True)
|
2019-05-19 14:33:58 +00:00
|
|
|
thread_id.start()
|
|
|
|
work_id = work_id+1 if work_id < 19 else 0
|
2019-05-14 18:23:30 +00:00
|
|
|
|
2019-05-15 12:58:03 +00:00
|
|
|
# if message received from queue, then some work was completed
|
2020-07-18 17:42:32 +00:00
|
|
|
if event == '-THREAD DONE-':
|
2019-05-15 00:59:12 +00:00
|
|
|
# LOCATION 3
|
2019-05-14 18:23:30 +00:00
|
|
|
# this is the place you would execute code at ENDING of long running task
|
2019-10-23 20:10:03 +00:00
|
|
|
# You can check the completed_work_id variable
|
|
|
|
# to see exactly which long-running function completed
|
2020-07-18 17:42:32 +00:00
|
|
|
completed_work_id = values[event]
|
2019-10-23 20:10:03 +00:00
|
|
|
window['-OUTPUT2-'].update(
|
|
|
|
'Complete Work ID "{}"'.format(completed_work_id))
|
2019-11-25 06:15:47 +00:00
|
|
|
window[completed_work_id].update(text_color='green')
|
2019-05-19 14:33:58 +00:00
|
|
|
|
2019-05-15 00:59:12 +00:00
|
|
|
if event == 'Popup':
|
2019-11-19 16:24:50 +00:00
|
|
|
sg.popup_non_blocking('This is a popup showing that the GUI is running', grab_anywhere=True)
|
2019-05-14 18:23:30 +00:00
|
|
|
# if user exits the window, then close the window and exit the GUI func
|
2019-10-23 20:10:03 +00:00
|
|
|
window.close()
|
2019-05-14 18:23:30 +00:00
|
|
|
|
2019-05-15 12:58:03 +00:00
|
|
|
############################# Main #############################
|
2019-05-14 18:23:30 +00:00
|
|
|
|
2019-10-23 20:10:03 +00:00
|
|
|
|
2019-05-14 18:23:30 +00:00
|
|
|
if __name__ == '__main__':
|
2019-05-15 00:59:12 +00:00
|
|
|
the_gui()
|
2019-10-23 20:10:03 +00:00
|
|
|
print('Exiting Program')
|