0

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()

BJonas88
  • 283
  • 4
  • 15
  • is your question simply how to play a `gif` in `tkinter` window? because that question has been answered here before and I am sure there are plenty of resources on how to do that, also how exactly did you try to do that? – Matiiss Sep 12 '21 at 08:51
  • You shouldn't call `tkinter` methods from threads other than the one where you created the `tk.Tk` window. Use `.after` scripts instead like [this](https://stackoverflow.com/a/459131/11106801) – TheLizzard Sep 12 '21 at 08:54
  • @Matiis Yes but with a twist. I want the GIF to play in tkinter at the same time the animation bar is loading. I have seen several answers in relation to that but nothing specifically addresses playing GIFs in a coherent manner, just basic stick animations. The comments in the M_95 definition above suggests what I'm trying to achieve. – BJonas88 Sep 13 '21 at 00:28
  • *"I'm trying to play a GIF and let it loop for 4 secs while loading a progress bar."* But in your code, it seems like you want to animate the GIF one cycle only instead of 4 secs. So which one do you want exactly: animate GIF one cycle or animate GIF up to 4 secs? – acw1668 Sep 13 '21 at 02:11
  • @TheLizzard thanks for the link. The first answer is pretty neat however I'm still stuck in the GIF part. Could you help with my suggestion above – BJonas88 Sep 13 '21 at 07:43
  • @acw1668 sorry for the confusion. One cycle of the GIF lasts for 4 secs...as well as the loading bar. So I'm trying to play one cycle of the GIF as the loading bar runs concurrently. – BJonas88 Sep 13 '21 at 07:45

1 Answers1

1

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:

  • use .after() to show the animated GIF because it is not safe to update tkinter widgets in a thread
  • use thread on loadingAnimation() instead
import 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
acw1668
  • 40,144
  • 5
  • 22
  • 34
  • You're a genius man! Nice work! The only minor issue is that a blank tkinter window opens after the GIF window closes and the script won't proceed until I manually close it. Any idea what I need to do to fix that? – BJonas88 Sep 13 '21 at 20:43
  • I found a soln. I just replaced ```root.deiconify( )``` with ```root.destroy```. Thanks again sir! – BJonas88 Sep 13 '21 at 21:17
  • final question: How would you approach running 2 GIF cycles in 4 secs? – BJonas88 Sep 14 '21 at 00:03
  • @BJonas88 Answer updated with animate GIF 2 cycles in 4 secs. – acw1668 Sep 14 '21 at 01:04