I'm having trouble inserting multiple images in a Listbox Widget for tkinter. When I'm inserting the new image, the previous one is gone. What should I do? Here is the code I'm having trouble with:
img = PhotoImage(file = Client.dir + "emo1.gif")
self.listBox.insert(END, sender)
self.listBox.image_create(END, image=img)
self.listBox.insert(END, "\n")
self.listBox.yview(END)
As the documentation states: (and comment by @BryanOakley)
The image object can then be used wherever an
imageoption is supported by some widget (e.g. labels, buttons, menus). In these cases, Tk will not keep a reference to the image. When the last Python reference to the image object is deleted, the image data is deleted as well, and Tk will display an empty box wherever the image was used.
Although the suggestion by @BryanOakley is definitely the simplest solution, it prevents unused images from being garbage collected which may be undesired.
Note: My suggested solution is assuming that self.listBox is a Text widget because the Listbox widget does not have a image_create method. If you are using a different kind of widget then you can still make a similar class to handle referencing the used images.
You could make a subclass of Text that keep a reference to the images inserted by overriding the relevant methods (image_create and delete being the most important):
from tkinter import Text #, PhotoImage, Tk
class Text_autoReferenceImage(Text):
def __init__(self,*varg,**kw):
self.images = {}
Text.__init__(self,*varg,**kw)
def image_create(self,index,**options):
img = options.get("image",None)
name = Text.image_create(self,index,**options)
if img is not None:
self.images[name] = img #this may remove previous reference with same name but different image
return name
def delete(self,*varg,**kw):
Text.delete(self,*varg,**kw)
self.clean_up_images()
def clean_up_images(self):
"""deletes reference to all images that are no longer present in Text widget (called by .delete())"""
images_still_in_use = self.image_names()
for name in set(self.images.keys()): #need to put .keys() into a set in python3 or it complains about dictionary changing size during iteration
if name not in images_still_in_use:
del self.images[name]
def destroy(self):
self.images.clear() #remove all references to own images
return Text.destroy(self)
Then if self.listBox is an instance of this class instead of Text it will handle the image references for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With