Merge pull request #2278 from PySimpleGUI/Dev-latest

Added animated GIF to tasks that take a long time but are unable to p…
This commit is contained in:
PySimpleGUI 2019-11-29 22:02:14 -05:00 committed by GitHub
commit dd13698d61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 22 additions and 12 deletions

View File

@ -5,12 +5,15 @@ import PySimpleGUI as sg
""" """
DESIGN PATTERN - Multithreaded Long Tasks GUI using shared global variables DESIGN PATTERN - Multithreaded Long Tasks GUI using shared global variables
Presents one method for running long-running operations in a PySimpleGUI environment. Presents one method for running long-running operations in a PySimpleGUI environment.
The PySimpleGUI code, and thus the underlying GUI framework, runs as the primary, main thread The PySimpleGUI code, and thus the underlying GUI framework, runs as the primary, main thread
The "long work" is contained in the thread that is being started. The "long work" is contained in the thread that is being started. Communicating is done (carefully) using global variables
The PySimpleGUI code is structured just like a typical PySimpleGUI program. A layout defined, There are 2 ways "progress" is being reported to the user. If a the amount of time is known ahead of time and
a Window is created, and an event loop is executed. the work can be broek down into countable units, then a progress bar is used. If a task is one long chunk
of time that cannot be broken down into smaller units, then an animated GIF is shown that spins as
long as the task is running.
""" """
thread_done = 1 thread_done = 1
@ -29,7 +32,7 @@ def long_operation_thread(seconds):
global thread_done, message, thread_counter, progress global thread_done, message, thread_counter, progress
print('Starting thread - will sleep for {} seconds'.format(seconds)) print('Thread started - will sleep for {} seconds'.format(seconds))
thread_counter += 1 thread_counter += 1
for i in range(int(seconds*10)): for i in range(int(seconds*10)):
time.sleep(.1) # sleep for a while time.sleep(.1) # sleep for a while
@ -50,23 +53,28 @@ def the_gui():
sg.change_look_and_feel('Light Brown 3') sg.change_look_and_feel('Light Brown 3')
layout = [[sg.Text('Long task to perform example')], layout = [[sg.Text('Long task to perform example')],
[sg.Output(size=(70, 12))], [sg.Output(size=(80, 12))],
[sg.Text('Number of seconds your task will take'), [sg.Text('Number of seconds your task will take'),
sg.Input(key='-SECONDS-', size=(5, 1)), sg.Input(key='-SECONDS-', size=(5, 1)),
sg.Button('Do Long Task', bind_return_key=True)], sg.Button('Do Long Task', bind_return_key=True),
sg.CBox('ONE chunk, cannot break apart', key='-ONE CHUNK-')],
[sg.Text('Work progress'), sg.ProgressBar(total, size=(20,20), orientation='h', key='-PROG-')], [sg.Text('Work progress'), sg.ProgressBar(total, size=(20,20), orientation='h', key='-PROG-')],
[sg.Button('Click Me'), sg.Button('Exit')], ] [sg.Button('Click Me'), sg.Button('Exit')], ]
window = sg.Window('Multithreaded Window', layout) window = sg.Window('Multithreaded Window', layout)
one_chunk = False
sg.popup_animated(None)
# --------------------- EVENT LOOP --------------------- # --------------------- EVENT LOOP ---------------------
while True: while True:
event, values = window.read(timeout=100) event, values = window.read(timeout=400)
if event in (None, 'Exit'): if event in (None, 'Exit'):
break break
elif event.startswith('Do'): elif event.startswith('Do'):
seconds = float(values['-SECONDS-']) seconds = float(values['-SECONDS-'])
print('Thread ALIVE! Long work....sending value of {} seconds'.format(seconds)) one_chunk = values['-ONE CHUNK-']
print('Thread Starting! Long work....sending value of {} seconds'.format(seconds))
threading.Thread(target=long_operation_thread, args=(seconds, ), daemon=True).start() threading.Thread(target=long_operation_thread, args=(seconds, ), daemon=True).start()
elif event == 'Click Me': elif event == 'Click Me':
print('Your GUI is alive and well') print('Your GUI is alive and well')
@ -75,11 +83,13 @@ def the_gui():
print('The thread has finished!') print('The thread has finished!')
print(f'message = {message}') print(f'message = {message}')
# reset everything for the next run # reset everything for the next run
thread_done = False sg.popup_animated(None) # just in case one's running, stop it
message = '' thread_done = one_chunk = False
progress = 0 message, progress = '', 0
window['-PROG-'].update_bar(total, total) # show the bar as maxed out window['-PROG-'].update_bar(total, total) # show the bar as maxed out
if progress != 0: if one_chunk: # flag signifies the thread is taking to take one big chunk of time
sg.popup_animated(sg.DEFAULT_BASE64_LOADING_GIF, background_color='white', transparent_color='white', time_between_frames=100)
elif progress != 0:
window['-PROG-'].update_bar(progress, total) # update the progress bar if non-zero window['-PROG-'].update_bar(progress, total) # update the progress bar if non-zero
# if user exits the window, then close the window and exit the GUI func # if user exits the window, then close the window and exit the GUI func