ealfonso
ealfonso

Reputation: 7322

Displaying images with Tkinter

I am working on a python program that displays a series of images using Tkinter and ImageTk. I have not been able to display more than a single image. Below is a small complete program that reproduces the error. The program searches the current directly recursively for jpg files, and displays them as the uses presses Enter.

import Tkinter, ImageTk,os, re


def ls_rec(direc):
    try:
        ls = os.listdir(direc)
    except Exception as e:
        return
    for f in os.listdir(direc):
        fpath = os.path.join(direc, f)
        if os.path.isfile(fpath):
            yield fpath
        elif os.path.isdir(fpath):
            for f2 in iterate_dir(os.path.join(direc,f)):
                yield f2

images = filter(lambda a:re.match('.*\\.jpg$',a),ls_rec(os.getcwd()))
assert(len(images)>10)
top = Tkinter.Tk()
image_label = Tkinter.Label(top)
Label_text = Tkinter.Label(top,text="Below is an image")
img = None
i = 0



def get_next_image(event = None):
    global i, img
    i+=1
    img = ImageTk.PhotoImage(images[i])
    label.config(image=img)
    label.image = img

top.bind('<Enter>',get_next_image)
label.pack(side='bottom')
Label_text.pack(side='top')
get_next_image()
top.mainloop()

The program fails with the following traceback:

Traceback (most recent call last):
  File "/usr/lib/python2.7/pdb.py", line 1314, in main
    pdb._runscript(mainpyfile)
  File "/usr/lib/python2.7/pdb.py", line 1233, in _runscript
    self.run(statement)
  File "/usr/lib/python2.7/bdb.py", line 387, in run
    exec cmd in globals, locals
  File "<string>", line 1, in <module>
  File "/home/myuser/Projects/sample_images.py", line 1, in <module>
    import Tkinter, ImageTk,os, re
  File "/home/myuser/Projects/sample_images.py", line 32, in get_next_image
    img = ImageTk.PhotoImage(some_image[1])
  File "/usr/lib/python2.7/dist-packages/PIL/ImageTk.py", line 109, in __init__
    mode = Image.getmodebase(mode)
  File "/usr/lib/python2.7/dist-packages/PIL/Image.py", line 245, in getmodebase
    return ImageMode.getmode(mode).basemode
  File "/usr/lib/python2.7/dist-packages/PIL/ImageMode.py", line 50, in getmode
    return _modes[mode]
KeyError: '/home/myuser/sampleimage.jpg'

Does anyone get the same behavior when running this code? What am I doing wrong?

EDIT: Using korylprince's solution, and a bit of cleaning, the following is a working version of the original code:

import os, re, Tkinter, ImageTk

def ls_rec(direc, filter_fun=lambda a:True):
    for (dirname, dirnames, fnames) in os.walk(direc):
        for fname in fnames:
            if filter_fun(fname):
                yield os.path.join(dirname,fname)


top = Tkinter.Tk()
image_label = Tkinter.Label(top)
text_label = Tkinter.Label(top,text="Below is an image")
images = ls_rec(os.getcwd(), lambda a:re.match('.*\\.jpg$',a))

imgL = []

def get_next_image(event = None):
    fname = images.next()
    print fname
    fhandle = open(fname)
    img = ImageTk.PhotoImage(file=fhandle)
    fhandle.close()
    imgL.append(img)
    image_label.config(image=img)


top.bind('<Return>',get_next_image)
image_label.pack(side='bottom')
text_label.pack(side='top')
get_next_image()
top.mainloop()

Edit: top.bind('<Enter>'...) actually bound the event of the mouse entering the frame, rather than user pressing Enter key. The correct line is top.bind('<Return>',...).

Upvotes: 0

Views: 5941

Answers (1)

korylprince
korylprince

Reputation: 3009

ImageTk.PhotoImage is not really documented properly.

You should try something like this:

#outside of functions
images = list()

#inside function
global images
with open(images[i]) as f:
    img = ImageTk.PhotoImage(file=f)
    images.append(img)

The reason for putting the image in the list is so that python will have a reference to it. Otherwise the garbage collector will delete the image object eventually.

Upvotes: 3

Related Questions