Why is Tkinter not displaying an image created from .configure() inside a class

Question:

I have a project made with Tkinter which involves buttons. These buttons have a command which resizes their images. The problem is that the images simply do not display. They only display if I create the image as a ImageTk.PhotoImage object outside the class and don’t interfere with the image in the init function. The skeleton of the method I used to do this is like so:

from tkinter import *
from PIL import Image, ImageTk

class GrowingButton(Button):
    def __init__(idx, *args, image=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.img = image
        self.grid(row=idx, column=0, sticky="news")
        if image:
            self.configure(command=self.expand, image=ImageTk.PhotoImage(image))
            self.image = ImageTk.PhotoImage(image)

    def expand(self):
        if self.img:
            self.img = self.img.resize((1, 1))
            self.configure(image=ImageTk.PhotoImage(image=self.img))
            self.image = ImageTk.PhotoImage(image=self.img)

root = Tk()
[root.rowspan(i, weight=1) for i in range(10)]
buttons = [GrowingButton(i, root, image=Image.open("")) for i in range(10)]
root.mainloop()

The issue may have to do with other parts of the code (though I doubt it). If that’s the case, please inform me and I’ll add other relevant code or maybe post a link the repository. This is a just a minimal reproducible example, but I’m completely stumped on why it doesn’t work.

Thanks in advance!

Asked By: user17301834

||

Answers:

Assigning self.image doesn’t change the button. You need to explicitly reconfigure the button whenever the image changes.

Also, you need to keep a reference to the image that is being used by the button. You’re creating two images: one used by the button, and a second identical image is being assigned to self.image. The one being used by the button isn’t being saved, so the garbage collected is destroying it when the function returns.

The code should be something like this:

self.image = ImageTk.PhotoImage(image=self.img)
self.configure(image=self.image)
Answered By: Bryan Oakley