Play an Animated GIF in python with tkinter

I am wanting to create a virtual pet style game using python3 and tkinter. So far I have the main window and have started putting labels in, but the issue I am having is playing an animated gif. I have searched on here and have found some answers, but they keep throwing errors. The result I found has the index position of the gif using PhotoImage continue through a certain range.

    # Loop through the index of the animated gif
frame2 = [PhotoImage(file='images/ball-1.gif', format = 'gif -index %i' %i) for i in range(100)]

def update(ind):

    frame = frame2[ind]
    ind += 1
    img.configure(image=frame)
    ms.after(100, update, ind)

img = Label(ms)
img.place(x=250, y=250, anchor="center")

ms.after(0, update, 0)
ms.mainloop()

When I run this in terminal with “pyhton3 main.py” I get the following error:

_tkinter.TclError: no image data for this index

What am I overlooking or completely leaving out?

Here is the link to the GitHub repository to see the full project:VirtPet_Python

Thanks in advance!

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

The error means that you tried to load 100 frames, but the gif has less than that.

Animated gifs in tkinter are notoriously bad. I wrote this code an age ago that you can steal from, but will get laggy with anything but small gifs:

import tkinter as tk
from PIL import Image, ImageTk
from itertools import count

class ImageLabel(tk.Label):
    """a label that displays images, and plays them if they are gifs"""
    def load(self, im):
        if isinstance(im, str):
            im = Image.open(im)
        self.loc = 0
        self.frames = []

        try:
            for i in count(1):
                self.frames.append(ImageTk.PhotoImage(im.copy()))
                im.seek(i)
        except EOFError:
            pass

        try:
            self.delay = im.info['duration']
        except:
            self.delay = 100

        if len(self.frames) == 1:
            self.config(image=self.frames[0])
        else:
            self.next_frame()

    def unload(self):
        self.config(image="")
        self.frames = None

    def next_frame(self):
        if self.frames:
            self.loc += 1
            self.loc %= len(self.frames)
            self.config(image=self.frames[self.loc])
            self.after(self.delay, self.next_frame)

root = tk.Tk()
lbl = ImageLabel(root)
lbl.pack()
lbl.load('ball-1.gif')
root.mainloop()

Method 2

First of all, you need to know what is the last range of your GIF file. so by changing the different value of i, you will get it.For my condition is 31.
then just need to put the condition.So it will play gif infinitely.

    from tkinter import *
    import time
    import os
    root = Tk()

    frames = [PhotoImage(file='./images/play.gif',format = 'gif -index %i' %(i)) for i in range(31)]

    def update(ind):
        frame = frames[ind]
        ind += 1
        print(ind)
        if ind>30: #With this condition it will play gif infinitely
            ind = 0
        label.configure(image=frame)
        root.after(100, update, ind)

    label = Label(root)
    label.pack()
    root.after(0, update, 0)
    root.mainloop()

Method 3

A very simple approach would be to use multithreading.

To run the GIF infinitely in a Tkinter window you should follow the following:

  1. Create a function to run the GIF.
  2. Put your code to run the GIF inside while True inside the function.
  3. Create a thread to run the function.
  4. Run root.mainloop() in the primary flow of the program.
  5. Use time.sleep() to control the speed of your animation.

Refer to my code below:

i=0
ph = ImageTk.PhotoImage(Image.fromarray(imageframes[i]))
imglabel=Label(f2,image=ph)
imglabel.grid(row=0,column=0)

def runthegif(root,i):
    
    while True:
        i = i + 7
        i= i % 150
        
        ph=ImageTk.PhotoImage(PhotoImage(file='images/ball.gif',format='gif -index %i' %i))
        imagelabel=Label(f2,image=ph)
        imagelabel.grid(row=0,column=0)
        time.sleep(0.1)
    


t1=threading.Thread(target=runthegif,args=(root,i))
t1.start()


root.mainloop()


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x