I'm trying to play a GIF and let it loop for 4 secs while loading a progress bar. I've tried so many combinations of solutions to no avail. Below is the closest I got. The loadingAnimation() function runs the progress bar well but I can't get the gif part together(M_95()). Ideally would love for the GIF to play in the middle of the screen at the same time the progress bar loads, then close the GIF window when it's finished.
import threading
import tkinter
root = tkinter.Tk()
frames = [PhotoImage(file='./myScripts/M-95.gif',format = 'gif -index %i' %(i)) for i in range(10)]
def M_95() :
# Play GIF (file name = m95.gif) in a 320x320 tkinter window
# Play GIF concurrently with the loading animation below
# Close tkinter window after play
def loadingAnimation(process):
while process.is_alive() :
animation = ["[■□□□□□□□□□]","[■■□□□□□□□□]", "[■■■□□□□□□□]", "[■■■■□□□□□□]", "[■■■■■□□□□□]", "[■■■■■■□□□□]", "[■■■■■■■□□□]", "[■■■■■■■■□□]", "[■■■■■■■■■□]", "[■■■■■■■■■■]"]
for i in range(len(animation)):
sys.stdout.write("\r | Loading..." + animation[i % len(animation)])
sys.stdout.flush()
time.sleep(0.4)
loading_process = threading.Thread(target = M_95)
loading_process.start()
loadingAnimation(loading_process)
loading_process.join()
First using while loop and time.sleep()
in the main thread of a tkinter application is not recommended because it will block tkinter mainloop()
and then cause the GUI not responding.
Suggest to:
.after()
to show the animated GIF because it is not safe to update tkinter widgets in a threadloadingAnimation()
insteadimport threading
import tkinter
import sys
import time
root = tkinter.Tk()
frames = [tkinter.PhotoImage(file='./myScripts/M-95.gif', format='gif -index %i'%(i)) for i in range(10)]
def center_window(win):
win.wait_visibility() # make sure the window is ready
x = (win.winfo_screenwidth() - win.winfo_width()) // 2
y = (win.winfo_screenheight() - win.winfo_height()) // 2
win.geometry(f'+{x}+{y}')
def M_95(n=0, top=None, lbl=None):
# Play GIF (file name = m95.gif) in a 320x320 tkinter window
# Play GIF concurrently with the loading animation below
# Close tkinter window after play
global process_is_alive # used in loadingAnimation()
delay = 4000 // len(frames) # make one cycle of animation around 4 secs
if n == 0:
root.withdraw()
top = tkinter.Toplevel()
lbl = tkinter.Label(top, image=frames[0])
lbl.pack()
center_window(top)
process_is_alive = True
if n < len(frames)-1:
lbl.config(image=frames[n])
lbl.after(delay, M_95, n+1, top, lbl)
else:
top.destroy()
root.deiconify()
process_is_alive = False
def loadingAnimation():
animation = ["[■□□□□□□□□□]","[■■□□□□□□□□]", "[■■■□□□□□□□]", "[■■■■□□□□□□]", "[■■■■■□□□□□]", "[■■■■■■□□□□]", "[■■■■■■■□□□]", "[■■■■■■■■□□]", "[■■■■■■■■■□]", "[■■■■■■■■■■]"]
i = 0
while process_is_alive:
sys.stdout.write("\r | Loading..." + animation[i % len(animation)])
sys.stdout.flush()
time.sleep(0.4)
i += 1
M_95() # start GIF animation
threading.Thread(target=loadingAnimation).start()
root.mainloop()
Update: animate GIF more than one cycle in around 4 secs:
def M_95(n=0, top=None, lbl=None):
# Play GIF (file name = m95.gif) in a 320x320 tkinter window
# Play GIF concurrently with the loading animation below
# Close tkinter window after play
global process_is_alive
num_cycles = 2
count = len(frames) * num_cycles
delay = 4000 // count # make required cycles of animation in around 4 secs
if n == 0:
root.withdraw()
top = tkinter.Toplevel()
lbl = tkinter.Label(top, image=frames[0])
lbl.pack()
center_window(top)
process_is_alive = True
lbl.after(delay, M_95, n+1, top, lbl)
elif n < count-1:
lbl.config(image=frames[n%len(frames)])
lbl.after(delay, M_95, n+1, top, lbl)
else:
top.destroy()
root.destroy()
process_is_alive = False