vincentlai
vincentlai

Reputation: 429

How to use python Tkinter to iterate images?

How to use python Tkinter to iterate images?

import tkinter as tk
from PIL import ImageTk, Image

win = tk.Tk()
win.geometry('800x500')  # set window size
win.resizable(0, 0)  # fix window

images = ['01.jpg', '02.jpg', '03.jpg']

def next_img():
   # show next image

for img in images:
    img = Image.open(img)
    img = ImageTk.PhotoImage(img)
    panel = tk.Label(win, image=img)
    panel.pack()
    btn = tk.Button(text='Next image', command=next_img)
    btn.pack()
win.mainloop()

But my panel doesn't show any images. I hope the panel waits me and I click the button to show next images. How to solve it.

Upvotes: 1

Views: 4316

Answers (2)

Aran-Fey
Aran-Fey

Reputation: 43136

The reason why your code doesn't display any images is a bit complicated. There are two factors working together:

  1. Because you're creating your labels (the ones that you use to display the images) in a loop, you end up creating 3 labels and 3 buttons - one for each image. All of these are arranged below each other, so depending on the size of your images, some of them might be below the window's bottom edge. If you use small images, you'll see three "Next image" buttons in your window.
  2. Tkinter images are garbage collected if you don't keep a reference to them in your python code. Since your loop overwrites the value of the img variable in each iteration, all images except the last one are garbage collected and aren't displayed.

To fix your code, first start by removing that loop. You don't need 3 labels and 3 buttons, and you don't need to load all 3 images immediately when the program starts either.

The code that loads and displays the image should be moved into the next_img function. You can update the label's image with the command panel['image'] = img.

In order to cycle through the list of images, it's easiest to use an iterator. You can turn your list of images into an iterator by calling images = iter(images). Then you can use the next function to get the next image from the iterator when you need it.

import tkinter as tk
from PIL import ImageTk, Image

win = tk.Tk()
win.geometry('800x500')  # set window size
win.resizable(0, 0)  # fix window

panel = tk.Label(win)
panel.pack()

images = ['01.jpg', '02.jpg', '03.jpg']
images = iter(images)  # make an iterator

def next_img():
    try:
        img = next(images)  # get the next image from the iterator
    except StopIteration:
        return  # if there are no more images, do nothing

    # load the image and display it
    img = Image.open(img)
    img = ImageTk.PhotoImage(img)
    panel.img = img  # keep a reference so it's not garbage collected
    panel['image'] = img

btn = tk.Button(text='Next image', command=next_img)
btn.pack()

# show the first image
next_img()

win.mainloop()

This code will loop through the images once, and when the last image is reached, pressing the "Next image" button will have no effect. If you want to wrap around to the first image, you can itertools.cycle to create an infinitely looping iterator instead:

images = itertools.cycle(images)

Upvotes: 8

Teavana
Teavana

Reputation: 11

Unfortunately, Tkinter is a little confusing and when placing an image in a label or button you will want to add on the line beneath panel.photo = img I'm not exactly sure why this works but it seems there are 2 values that take the image to display it.

Upvotes: 1

Related Questions