Do you have any idea why your program didn't work?
I cleaned up your program a little and ran it..
import tkinter as tk
image_files = [
"dice1.png",
"dice2.png",
"dice3.png",
"dice4.png",
"dice5.png",
"dice6.png",
]
ws = tk.Tk()
l = tk.Label(ws, font="bold")
l.pack()
index = 0
def move():
global index
img = tk.PhotoImage(file=image_files[index])
tk.Label(ws, image=img).pack()
index = (index + 1) % len(image_files)
ws.after(2000, move)
move()
ws.mainloop()
When I run this program I don't see any images. The window also gets taller every two seconds.
I remember reading something about images in tkinter buttons and labels. tkinter doesn't keep a reference to the image, leaving that to your program. If you don't keep a reference to the image the reference count drops to zero and the image is marked for disposal. When the image is garbage collected it cannot be drawn. I modify my program to keep a refence to the image.
import tkinter as tk
image_files = [
"dice1.png",
"dice2.png",
"dice3.png",
"dice4.png",
"dice5.png",
"dice6.png",
]
ws = tk.Tk()
l = tk.Label(ws, font="bold")
l.pack()
index = 0
def move():
global index
global img # This keeps the image in a global variable. I should see images now.
img = tk.PhotoImage(file=image_files[index])
tk.Label(ws, image=img).pack()
index = (index + 1) % len(image_files)
ws.after(2000, move)
move()
ws.mainloop()
When I run this program I see an image, but the window is still growing every two seconds. That is probably caused by creating and packing a new Label object each time I change the image. I am going to change my program to reuse the same label.
import tkinter as tk
image_files = [
"dice0.png",
"dice1.png",
"dice2.png",
"dice3.png",
"dice4.png",
"dice5.png",
"dice6.png",
]
ws = tk.Tk()
image_label = tk.Label(ws, font="bold")
image_label.pack()
index = 0
def move():
global index
global img
img = tk.PhotoImage(file=image_files[index])
image_label["image"] = img
index = (index + 1) % len(image_files)
ws.after(2000, move)
move()
ws.mainloop()
Now the window doesn't grow each time a new image is displayed. If there was just a way to get rid of those horrible global variables. Oh! I know! I will make a class to keep all the info needed for the slideshow.
import tkinter as tk
import itertools
images = ["dice1.png", "dice2.png", "dice3.png", "dice4.png", "dice5.png", "dice6.png"]
class ImageViewer(tk.Tk):
"""A tkinter window that displays images like a slideshow"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Label to display the image
self.image_label = tk.Label(self)
self.image_label.pack()
# Label to display the image file name
self.name_label = tk.Label(self, width=30)
self.name_label.pack()
self.image = None
self.delay = 2000
self.running = False
def start(self, image_files, loop=True, delay=None):
"""
Start slide show. Set loop to True to cycle through images forever.
Set delay to seconds that image is shown.
"""
if loop:
"""Cycle forever"""
self.image_files = itertools.cycle(image_files)
else:
"""Show slides once"""
self.image_files = iter(image_files)
if delay is not None:
self.delay = delay * 1000
self.running = True
self.update_image()
def stop(self):
"""Stop slideshow"""
self.running = False
def update_image(self):
"""Show the next image"""
if self.running:
try:
image_file = next(self.image_files)
self.name_label["text"] = image_file
self.image = tk.PhotoImage(file=image_file)
self.image_label["image"] = self.image
self.after(self.delay, self.update_image)
except StopIteration:
self.running = False
viewer = ImageViewer()
viewer.start(images, loop=True, delay=1)
viewer.mainloop()