0

According to this tutorial: https://www.tutorialspoint.com/how-to-update-an-image-in-a-tkinter-canvas#:~:text=To%20change%20a%20particular%20image,in%20the%20same%20project%20directory.

this should work: canvas.itemconfig(imageObject, image=newPhotoImage)

But in fact, the following code which seems to follow that pattern, does not work. The first image snap1.jpg appears correctly. But once the update function executes, the canvas goes blank. image.show() reveals that the files were in fact correctly loaded. So I am mystified. What is missing? No exception, no warning message.

from tkinter import *
from PIL import Image, ImageTk

def imagery(root):
    global image1
    global canvas, log1, snaps2, i1, counter, sizeX, sizeY

    image = Image.open("snap1.jpg")
    sizeX, sizeY = image.size
    canvas= Canvas(root, width= sizeX // 2, height= sizeY // 2)
    canvas.grid(column=0, row=0)
    image1 = ImageTk.PhotoImage(image.resize((sizeX // 2, sizeY // 2)))
    i1 = canvas.create_image(0, 0, anchor='nw',image=image1)
    root.after(2000, update)
    return canvas

def update():
    global counter
    image = Image.open("snap2.jpg")
    image.show()
    image1 = ImageTk.PhotoImage(image.resize((sizeX // 2, sizeY // 2)))
    canvas.itemconfig(i1, image=image1)

if __name__ == "__main__":
    root = Tk()
    root.grid()
    canvas = imagery(root)
    root.mainloop()
Joymaker
  • 813
  • 1
  • 9
  • 23

1 Answers1

1

The answer was simple but devious, and highlights a very strange quirk of tkinter. Contrary to all normal Python memory management protocol, tkinter does not keep a reference to the PhotoImage object that it displays. Therefore you must, to prevent it from being garbage collected. As long as the image is intended to be visible, there must be a live reference to the PhotoImage held somewhere in your code. The simplest solution is this tiny modification to hold the reference in a global variable:

def update():
    global counter, image1
    . . .
Joymaker
  • 813
  • 1
  • 9
  • 23