| Images |
UserPreferences |
| Tkinter Wiki | FrontPage | RecentChanges | TitleIndex | WordIndex | SiteNavigation | HelpContents | moin.sf.net |
Something that seems to bite every new Tkinter programmer at least once: you've loaded a PhotoImage, applied it to a Button, Label, or other widget, and nothing shows up - because you referenced the image only via a local variable, so it went out of scope and got deleted before the widget ever appeared. The usual solution is to store a reference to the image as an attribute of the widget that is to display it.
You might just call this a bug in Tkinter, but the reality isn't quite that simple... Tk images are not first-class objects: when you apply one to a widget, you do not in any sense "pass a reference to" the image. Instead, you just pass a name, which Tk looks up in an internal table of defined images (from which images can only be deleted manually). From Tkinter, passing a PhotoImage as a parameter actually only sends the str() of the image object to the Tcl side: this is just a string, the randomly-generated name assigned when the object was created. "No reference to the image itself" means "no reference counting" means "no way for the Python side to be notified when the image is truly no longer used". If Tkinter didn't delete images when no Python reference to them existed, they would be unavoidable memory leaks.
Tkinter could automatically store a reference to the image object itself when one is passed as a parameter to a widget method, but this would actually be worse in some cases. Consider that the image could become unused without the Python side being aware of it: for example, if an image is inserted in a Text widget, but the user later deletes the text containing it. An automatically-generated reference would make the image object leak in this case.
The only workable improvement I can think of is for PhotoImage.__del__ to only immediately delete the image if Tk's image inuse command showed them to currently be unused. Otherwise, the image name would be added to a list of orphaned images; periodically (via after()?), Tkinter would scan this list for images that are no longer inuse and delete them then. Possible problem: if an image was inserted in a Text widget and was later deleted, but the deletion is still in the widget's undo stack, does the image count as inuse?
1 2 3 4 | def subimage(src, l, t, r, b):
dst = PhotoImage()
dst.tk.call(dst, 'copy', src, '-from', l, t, r, b, '-to', 0, 0)
return dst |