Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inserting multiple images Tkinter

Tags:

python

tkinter

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)
like image 597
user6036956 Avatar asked Aug 07 '26 08:08

user6036956


1 Answers

As the documentation states: (and comment by @BryanOakley)

The image object can then be used wherever an image option 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.

like image 112
Tadhg McDonald-Jensen Avatar answered Aug 09 '26 02:08

Tadhg McDonald-Jensen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!