4

I am trying to display an image in a window...seems simple enough right? Well I have a big bug!

I have this exact same code in one file:

import Tkinter

root = Tkinter.Tk()
canvas = Tkinter.Canvas(root)
canvas.grid(row = 0, column = 0)
photo = Tkinter.PhotoImage(file = '/Users/Richy/Desktop/1.gif')
image1 = canvas.create_image(0,0, image=photo)
root.mainloop()

It works.

I have this in part of a bigger file:

def officialPictureWindow(self):
    t = Toplevel(self)
    t.wm_title("Official Image")
    self.__canvas3 = Canvas(t)
    self.__canvas3.grid(row = 0, column = 0)
    photo = PhotoImage(file = '/Users/Richy/Desktop/1.gif')
    image1 = self.__canvas3.create_image(0,0, image=photo)

It doesn't work!

That function is called when someone presses a button on a menubar I have. All the other menubar buttons I have operate properly and show their windows. There's no images in the others though.

This gives no no error. Just a blank screen. Does anyone know why?

martineau
  • 119,623
  • 25
  • 170
  • 301
user3159537
  • 61
  • 1
  • 12

1 Answers1

11

You need to keep an additional reference to photo so it doesn't get prematurely garbage collected at the end of the function. An Introduction to Tkinter explains further:

Note: When a PhotoImage object is garbage-collected by Python (e.g. when you return from a function which stored an image in a local variable), the image is cleared even if it’s being displayed by a Tkinter widget.

To avoid this, the program must keep an extra reference to the image object. A simple way to do this is to assign the image to a widget attribute, like this:

label = Label(image=photo)
label.image = photo # keep a reference!
label.pack()

In your case, you could attach the image to your self variable, or maybe the canvas. It doesn't really matter, as long as it is assigned to something.

self.image = photo
#or:
self.__canvas3.image = photo
Community
  • 1
  • 1
Kevin
  • 74,910
  • 12
  • 133
  • 166
  • label = Label(image=photo), so I think photo is referenced already in label object, – Xiaoyong Guo May 29 '21 at 15:55
  • 1
    It _is_ referenced in the line that creates the photo object, but the reference count for photo still drops to zero at the end of the expression, and photo ceases to exist. This behavior can be surprising because most custom classes will retain at least one reference to any arguments that it needs to make use of later. But Label and other Tkinter widgets are essentially thin wrappers over Tcl classes implemented in C, which don't go out of their way to handle the reference counts of its arguments. – Kevin May 29 '21 at 18:29