This question already has answers here:
Play an Animated GIF in python with tkinter
(3 answers)
Closed 5 years ago.
I've been trying to play an animated gif using Tkinter.PhotoImage, but haven't been seeing any success. It displays the image, but not the animation. The following is my code:
root = Tkinter.Tk()
photo = Tkinter.PhotoImage(file = "path/to/image.gif")
label = Tkinter.Label(image = photo)
label.pack()
root.mainloop()
It displays the image in a window, and that's it. I'm thinking that the issue has something to do with Tkinter.Label but I'm not sure. I've looked for solutions but they all tell me to use PIL (Python Imaging Library), and it's something that I don't want to use.
With the answer, I created some more code (which still doesn't work...), here it is:
from Tkinter import *
def run_animation():
while True:
try:
global photo
global frame
global label
photo = PhotoImage(
file = photo_path,
format = "gif - {}".format(frame)
)
label.configure(image = nextframe)
frame = frame + 1
except Exception:
frame = 1
break
root = Tk()
photo_path = "/users/zinedine/downloads/091.gif"
photo = PhotoImage(
file = photo_path,
)
label = Label(
image = photo
)
animate = Button(
root,
text = "animate",
command = run_animation
)
label.pack()
animate.pack()
root.mainloop()
Thanks for everything! :)
You have to drive the animation yourself in Tk. An animated gif consists of a number of frames in a single file. Tk loads the first frame but you can specify different frames by passing an index parameter when creating the image. For example:
frame2 = PhotoImage(file=imagefilename, format="gif -index 2")
If you load up all the frames into separate PhotoImages and then use timer events to switch the frame being shown (label.configure(image=nextframe)). The delay on the timer lets you control the animation speed. There is nothing provided to give you the number of frames in the image other than it failing to create a frame once you exceed the frame count.
See the photo Tk manual page for the official word.
Here's a simpler example without creating an object:
from tkinter import *
import time
import os
root = Tk()
frameCnt = 12
frames = [PhotoImage(file='mygif.gif',format = 'gif -index %i' %(i)) for i in range(frameCnt)]
def update(ind):
frame = frames[ind]
ind += 1
if ind == frameCnt:
ind = 0
label.configure(image=frame)
root.after(100, update, ind)
label = Label(root)
label.pack()
root.after(0, update, 0)
root.mainloop()
Related
This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 8 months ago.
I've tried several methods but did not worked. Suppose I am working on a project that changes the picture when the button is clicked.
Well as I know, all it did is I just clicked 1 time and the image turned white and I can not click it anymore. Quick! I need to complete this project in 1 hour deadline. Here is the code.
# Modules
from tkinter import *
from PIL import Image, ImageTk
# Functions
def change_img():
global curr_img
global root
global image1
image1 = Image.open(f"Hamster {curr_img + 1}.jpg")
image1 = image1.resize((100, 60))
img1 = ImageTk.PhotoImage(image1)
btn.configure(image=img1, command=change_img)
root.update()
curr_img += 1
# Main Window
root = Tk()
root.title("Picture Change")
root.geometry("300x150")
root.config(bg="black")
# Adding Objects
curr_img = 1
Label(root, text="My Favorite Animal", fg="white", bg="black", font=("Arial bold", "20")).pack() # This is a label.
image1 = Image.open("Hamster 1.jpg") # First we open the image and save it into a variable.
image1 = image1.resize((100,60)) # Resizes the image.
img1 = ImageTk.PhotoImage(image1) # Create a ImageTK object from the image1 variable.
btn = Button(image = img1, command=change_img) # Create a label and put the image into it.
btn.pack() # Pack the label that contains the image. Now, we repeat the process.
# Mainloop
root.mainloop()
Thanks if the answer is quick and accurate. Comment, thanks very much too.
You create the next image in the change_img() function and when the function exits the reference to the image is garbage collected. You can save a reference to the image in the button widget:
btn.configure(image=img1, command=change_img)
btn.image = img1 # Save a reference to the new image
I have a issue in tkinter for python 3. I would like to create an animating game character in python, tkinter without using PIL. I found a way to animate the character using a gif, but I do not know how to move the gif I tried to use canvas.move
here is my code:
from tkinter import *
import os
import time
root = Tk()
c = Canvas(root,width = 500,height = 500)
c.pack()
frames = [PhotoImage(file=(os.path.expanduser("~/Desktop/DaQueenIDLE.gif")),format = 'gif -index %i' % (i)) for i in range(2)]
def update(ind):
frame = frames[ind]
ind += 1
if ind >= 2:
ind = 0
label.configure(image=frame)
root.after(100, update, ind)
label = Label(root)
label.pack()
root.after(0, update, 0)
c.move(frames,0,-100)
root.update()
root.mainloop()
move is a method for Canvas, and its first argument needs to be an item on Canvas.
In your case frames is not an item on the Canvas.
Replace:
def update(ind):
#...
label.configure(image=frame)
root.after(100, update, ind)
label = Label(root)
label.pack()
with:
def update(ind):
#...
c.itemconfig(character, image=frame)
c.move(character, 1, 1)
root.after(100, update, ind)
character = c.create_image((47,47), image=frames[0])
To convert your label into an image item in Canvas and move it.
Example
Below is a complete example that downloads(you can comment download_images out after the initial run) .gif images below online:
and then moves an image while animating between the two:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except ImportError:
import Tkinter as tk
def download_images():
# In order to fetch the image online
try:
import urllib.request as url
except ImportError:
import urllib as url
url.urlretrieve("https://i.stack.imgur.com/57uJJ.gif", "13.gif")
url.urlretrieve("https://i.stack.imgur.com/8LThi.gif", "8.gif")
def animate_and_move(i):
i = (i + 1) % 2
canvas.itemconfig(moving_image, image=canvas.images[i])
canvas.move(moving_image, 1, 1)
canvas.after(100, animate_and_move, i)
if __name__ == '__main__':
download_images() # comment out after initial run
root = tk.Tk()
canvas = tk.Canvas(root, height=644, width=644, bg='#ffffff')
canvas.images = list()
canvas.images.append(tk.PhotoImage(file="8.gif"))
canvas.images.append(tk.PhotoImage(file="13.gif"))
moving_image = canvas.create_image((164, 164), image=canvas.images[0])
animate_and_move(0)
canvas.pack()
root.mainloop()
Note that if:
import tkinter
tkinter.TkVersion >= 8.6
returns True then .png files are also supported without an additional library.
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!
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()
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()
A very simple approach would be to use multithreading.
To run the GIF infinitely in a Tkinter window you should follow the following:
Create a function to run the GIF.
Put your code to run the GIF inside while True inside the function.
Create a thread to run the function.
Run root.mainloop() in the primary flow of the program.
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()
So I made a script in python with Tkinter and the thing is that the first Tkinter window pops up without problems but when the code goes to the second window it says :
_tkinter.TclError: image "pyimage1" doesn't exist
and I didn't find anything that helped me, could someone help me please ?
Here is the code :
from Tkinter import *
from PIL import ImageTk, Image
def choose():
global name, chosen
name = name1.get()
chosen = chosen1.get()
print name
print chosen
root0.quit()
root0 = Tk()
name1 = Entry(root0)
name1.pack()
chosen1 = Entry(root0)
chosen1.pack()
Button(root0, text="ENTER", command=choose).pack()
root0.mainloop()
root = Tk()
img = ImageTk.PhotoImage(Image.open('person1.png'))
panel1 = Label(root, image = img)
panel1.pack(side="left")
img2 = ImageTk.PhotoImage(Image.open('person2.png'))
panel2 = Label(root, image = img2)
panel2.pack(side="right")
root.mainloop()
by the way, the python version is 2.7
This is a side effect of using 2 roots (Tk() instances). The images default to associate with the first root window. The quick fix is to provide the image with the correct root:
img2 = ImageTk.PhotoImage(Image.open('person2.png'), master=root)
The proper fix is to never use more than one Tk(). Put all your code into Frame instances, and then destroy one and load the other when the time is right:
import Tkinter as tk
def choose():
global name, chosen
name = name1.get()
chosen = chosen1.get()
print name
print chosen
frame0.destroy() # kill this frame
frame1.pack() # open new frame
root = tk.Tk()
frame0 = tk.Frame(root)
name1 = tk.Entry(frame0)
name1.pack()
chosen1 = tk.Entry(frame0)
chosen1.pack()
tk.Button(frame0, text="ENTER", command=choose).pack()
frame1 = tk.Frame(root)
img = ImageTk.PhotoImage(Image.open('person1.png'))
panel1 = tk.Label(frame1, image = img)
panel1.pack(side="left")
img2 = ImageTk.PhotoImage(Image.open('person2.png'))
panel2 = tk.Label(frame1, image = img2)
panel2.pack(side="right")
#start the program
frame0.pack() # load frame0
root.mainloop()
Note I also moved you away from the evil wildcard imports (from module import *).
This question already has an answer here:
Video output within Tkinter?
(1 answer)
Closed 6 years ago.
I currently have this code for opening up a .mp4 file from a tkinter program.
import os
from tkinter import *
app = Tk()
app.title('Video Player')
Fcanvas = Canvas(bg="black", height=600, width=170)
def snd1():
os.system("C:\\Users\Burky\\Desktop\\Videos\\PermsAndCombsVideo.mp4")
var = IntVar()
rb1 = Radiobutton(app, text= "Play Video", variable = var, value=1, command=snd1)
rb1.pack(anchor = W)
Fcanvas.pack()
app.mainloop()
This is good, although the video opens up within quick-time player and is not embedded within the window, is there a way to implement this into the main window instead of it opening up in the quick-time player?
thanks
Here's one way to do it. This will continuously update the labels image to be the frames of the video specified. You'll have to handle sound if you want that too. This should get you started.
import tkinter as tk, threading
import imageio
from PIL import Image, ImageTk
video_name = "test.mkv" #This is your video file path
video = imageio.get_reader(video_name)
def stream(label):
for image in video.iter_data():
frame_image = ImageTk.PhotoImage(Image.fromarray(image))
label.config(image=frame_image)
label.image = frame_image
if __name__ == "__main__":
root = tk.Tk()
my_label = tk.Label(root)
my_label.pack()
thread = threading.Thread(target=stream, args=(my_label,))
thread.daemon = 1
thread.start()
root.mainloop()