Search code examples
pythontkinterlabelloading

Python Tkinter Label not responding


I am trying to make a loading and a GIF would be a lot helpful if it was supported in python tkinter. But since it is not supported, so I put all the frame-by-frame pictures in the list that makes a loading when played continuously (using assign_pic function) and then I created a label (called lab_loading) of which I change the picture after 200ms by calling the start_anim function. I am calling the assign_pic function in a loop which I think causes this error. See my source code below 👇 and the video I provided to understand this problem clearly.

Video: https://drive.google.com/file/d/1WHwZqvd8vXz-ehXbQ_fRtrKPEyFLKrVe/view?usp=sharing

Source code:

from time import sleep
from tkinter import Tk, Label
from PIL import ImageTk, Image


class Loading(Tk):
    def __init__(self):
        super().__init__()
        self.title('Loading')
        self.geometry('250x217')

        self.address = getcwd()
        self.imgs_list = []
        self.loadingImgsList(self.address)

    # This method Puts all the images in the list
    def loadingImgsList(self, curAddress):
        address = f'{curAddress}\\loading'
        self.imgs_list = [(ImageTk.PhotoImage(Image.open(
            f"{address}\\{i}.png"))) for i in range(1, 4)]

    # This mehtod assigns the picture from the list via index (ind) number from the imgs_list list and
    # updates the GUI when called.
    def assign_pic(self, ind):
        lab_loading.config(image=self.imgs_list[ind])
        self.update_idletasks()
        sleep(0.2)

    def start_anim(self):
        ind = 0
        b = 0
        while (b < 300):
            if ind == 2:
                ind = 0
            else:
                ind += 1

            self.after(200, self.assign_pic, ind)
            b += 1


if __name__ == "__main__":
    root = Loading()
    lab_loading = Label(root, image='')
    lab_loading.pack()
    root.start_anim()
    root.mainloop()

I Tried to make start_anime function recursive but it was still the same. I don't know why this is happening. I also made the loop finite but it was still not working. So a solution to this problem or even a better suggestion would highly be appreciated.


Solution

  • you shouldn't be using sleep inside tk, as it blocks python from handling user actions.

    the way you do animation in tk is by using the after method, to call a function that would update the canvas, this function will call after again, until the animation is complete.

    # everything before this function should be here
    
        self.ind = 0 #somewhere in __init__
        def assign_pic(self):
            if self.ind < len(imgs_list):
                lab_loading.config(image=self.imgs_list[self.ind])
                self.ind += 1
                root.after(500,self.assign_pic) # time in milliseconds
            else:
                print("done") # do what you want after animation is done
    
    if __name__ == "__main__":
        root = Loading()
        lab_loading = Label(root, image='')
        lab_loading.pack()
        root.after(100,root.assign_pic)
        root.mainloop()
    

    the after function schedules the given function after a certain delay, during which the GUI is free to respond to any action.

    Edit: after method takes argument in milliseconds not in seconds, i had the input in it in seconds instead of milliseconds, it's now fixed.