0

I have created a python class which inherits Tk from tkinter library. I want to add a label with an image to it but it only works when I create a Photoimage as variable to 'self'.

This code works:

class HMIDrawer(Tk):

    def __init__(self):
        super().__init__()

        self.frame = Frame(self)
        self.img = PhotoImage(file='resources/platoontomtom_empty.png')
        self.label = Label(self.frame, image=self.img, bg='white')
        self.label.pack()
        self.frame.pack()
        self.mainloop()

And this code doesn't work:

class HMIDrawer(Tk):

    def __init__(self):
        super().__init__()

        self.frame = Frame(self)
        img = PhotoImage(file='resources/platoontomtom_empty.png')
        self.label = Label(self.frame, image=img, bg='white')
        self.label.pack()
        self.frame.pack()
        self.mainloop()

Can anyone explain why the first code does work and the second code doesn't?

progmatico
  • 4,714
  • 1
  • 16
  • 27
suitendaal
  • 149
  • 9
  • https://stackoverflow.com/questions/68282/why-do-you-need-explicitly-have-the-self-argument-into-a-python-method – TmSmth Apr 12 '18 at 13:25
  • 1
    @TmSmth: the problem is not at all related to the explicit use of `self` in a Python method, which is the topic of the link you propose. The problem here comes from the garbage collector vs. persistent references – sciroccorics Apr 12 '18 at 13:50
  • @sciroccorics ok, just read your answer, thanks for the explanation ! – TmSmth Apr 12 '18 at 14:08

1 Answers1

4

PhotoImage reads the image data from file and stores it in memory as a pixel buffer. The reference of this buffer has to be persistent as long as the application runs (or at least, as long the Label widget showing the image exists).

If you put the result of PhotoImage in a local variable (e.g. img, as in the second code), the garbage collector is likely to destroy the data referenced by this local variable. On the other hand, if you store the reference of your pixel buffer in an attribute (e.g. self.img, as in the first code) the garbage collector will not destroy your data as long as self exists, which means as long as the application runs...

If your GUI uses many images, a usual practice is to create an attribute self.images that puts all required images either in a tuple or a dictionary (whether you prefer indexing them by numbers or by strings), that ensures that all images will be kept in memory.

sciroccorics
  • 2,357
  • 1
  • 8
  • 21