69

This code works:

import tkinter

root = tkinter.Tk()
canvas = tkinter.Canvas(root)
canvas.grid(row = 0, column = 0)
photo = tkinter.PhotoImage(file = './test.gif')
canvas.create_image(0, 0, image=photo)
root.mainloop()

It shows me the image.

Now, this code compiles but it doesn't show me the image, and I don't know why, because it's the same code, in a class:

import tkinter

class Test:
    def __init__(self, master):
        canvas = tkinter.Canvas(master)
        canvas.grid(row = 0, column = 0)
        photo = tkinter.PhotoImage(file = './test.gif')
        canvas.create_image(0, 0, image=photo)

root = tkinter.Tk()
test = Test(root)
root.mainloop()
Bryan Oakley
  • 341,422
  • 46
  • 489
  • 636
thomas.winckell
  • 1,047
  • 1
  • 9
  • 16
  • 2
    http://effbot.org is down. The gist of it is that the image is passed by reference. If the reference is to a local variable, the memory referenced gets reused and the reference becomes stale. The variable storing the image should be in the same scope (has to have the same lifetime) as the Tk gui object it appears on. – maszoka Jan 31 '21 at 01:26
  • @maszoka: `effbot.org` may be down, but you can still read the link [Why do my Tkinter images not appear?](https://web.archive.org/web/20201111190625id_/http://effbot.org/pyfaq/why-do-my-tkinter-images-not-appear.htm) thanks to the Internet Archive [wayback machine](https://archive.org/web/web.php). – martineau Oct 05 '21 at 13:35
  • 1
    Also note that the same problem can appear anywhere temporary `PhotoImage`s are used, for example in a calling sequence such as `label = Label(image=ImageTk.PhotoImage(Image.fromarray(data)))`. – martineau Feb 26 '22 at 15:51

4 Answers4

97

The variable photo is a local variable which gets garbage collected after the class is instantiated. Save a reference to the photo, for example:

self.photo = tkinter.PhotoImage(...)

If you do a Google search on "tkinter image doesn't display", the first result is this:

Why do my Tkinter images not appear? (The FAQ answer is currently not outdated)

martineau
  • 112,593
  • 23
  • 157
  • 280
Bryan Oakley
  • 341,422
  • 46
  • 489
  • 636
6
from tkinter import *
from PIL import ImageTk, Image

root = Tk()

def open_img():
    global img
    path = r"C:\.....\\"
    img = ImageTk.PhotoImage(Image.open(path))
    panel = Label(root, image=img)
    panel.pack(side="bottom", fill="both")
but1 = Button(root, text="click to get the image", command=open_img)
but1.pack()
root.mainloop() 

Just add global to the img definition and it will work

TIRTH SHAH
  • 79
  • 1
  • 2
  • This answer is fine for a program that just uses functions, but if, as in the OP's case, you use a class, than `global` is _not_ the way to go. – Sylvester Kruin Jan 07 '22 at 16:44
1

The problem is Python automatically deletes the references to the variable by a process known as Garbage Collection. The solution is to save the reference or to create a new reference.

The following are the ways:

  1. Using self to increase the reference count and to save the reference.
import tkinter

class Test:
    def __init__(self, master):
        canvas = tkinter.Canvas(master)
        canvas.grid(row = 0, column = 0)
        self.photo = tkinter.PhotoImage(file = './test.gif') # Changes here
        canvas.create_image(0, 0, image=self.photo) # Changes here

root = tkinter.Tk()
test = Test(root)
root.mainloop()
  1. Saving it to a list to increase the reference count and to save the reference.
import tkinter
l=[]
class Test:

    def __init__(self, master):
        canvas = tkinter.Canvas(master)
        canvas.grid(row = 0, column = 0)
        photo = tkinter.PhotoImage(file = './test.gif')
        l.append(photo)
        canvas.create_image(0, 0, image=photo)

root = tkinter.Tk()
test = Test(root)
root.mainloop()

While using method 2, you can either make a global list as i did or use list inside the class. Both would work.

Some useful links:

Faraaz Kurawle
  • 923
  • 3
  • 22
0

Just add global photo as the first line inside the function.

Gabriel
  • 37
  • 3