unsettling tkinter bug -- or is it just me?

Kevin Russell krussell4 at videon.home.com
Tue Jun 13 12:13:55 EDT 2000


Bob Lewis wrote:

> Consider the following code:
> --------
> from Tkinter import *
>
> root = Tk()
> img = PhotoImage(file='bobl.gif')
>
> def func():
>     cnvs = Canvas(root, width=img.width(), height=img.height())
>     cnvs.create_image(0,0, image=img, anchor=NW)
>     cnvs.pack(side=TOP)
>     Button(root, text='Quit', command=root.quit).pack()
>
> func()
> root.mainloop()
> --------
> This runs just fine: It creates a root toplevel with "bobl.gif" displayed
> in it and a "Quit" button.
>
> Now we make one wafer-thin change: Move the the "img =" inside "func()":
> --------
> from Tkinter import *
>
> root = Tk()
>
> def func():
>     img = PhotoImage(file='bobl.gif')
>     cnvs = Canvas(root, width=img.width(), height=img.height())
>     cnvs.create_image(0,0, image=img, anchor=NW)
>     cnvs.pack(side=TOP)
>     Button(root, text='Quit', command=root.quit).pack()
>
> func()
> root.mainloop()
> --------
> And now, while the canvas has the right dimensions, the image does
> not appear.  Okay, so "img" went from a global to local scope, but
> that shouldn't have affected execution, right?  Have I missed something?
>
> This is on a Red Hat Linux system running versions 1.5.2-13 of both
> python and tkinter.
>
>         - Bob Lewis
>           bobl at tricity.wsu.edu

I've noticed this ... um ... feature myself, but have never quite got
around to asking c.l.p about it.  It bit me when I tried to create a bunch
of  buttons with images, using a for-loop, like:

buttonlist = [('1.gif', SaveFunction), ('2.gif', OpenFunction), ...... ]
for (imagefile, command) in buttonlist:
    img = PhotoImage(file=imagefile)
    Button(toolbar, image=img, command=command).pack()

[Remembering it off the top of my head, so it may have mistakes
in it.]

Anyway, once the img variable gets reassigned, the PhotoImage
object that it used to refer to won't show up anymore.

It seems that you have to keep an active Python reference to a
PhotoImage -- the reference you'd expect its parent Tk object
to keep to it isn't good enough.  (Maybe the garbage collector is
over-eager.  Who knows?)

I got around it by making a global Python list of PhotoImage
objects, and just appending to it every time I make a new one.
Ugly hack, but it works.  If anyone has a more elegant solution,
I'd appreciate hearing it.

-- Kevin






More information about the Python-list mailing list