Tkinter Vanishing Photoimage Issue

Tkinter vanishing PhotoImage issue

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

Why are these images disappearing and how can I fix it (python)?

I don't think I understand why this should be, but the problem is, in fact, that the ImageTk.PhotoImage instances evaporate when the function ends. That shouldn't be the case. The Label widget should be holding a reference that keeps it alive, but if you store those PhotoImage objects in a list, as below, the code works:

  def Hand(self):
self.but.destroy()
self.newCard = random.sample(self.cardsList, k=9)
self.keep = []
self.ext()

def download(self, url, ex, ey):
with urllib.request.urlopen(url) as u:
raw_data = u.read()
img = Image.open(BytesIO(raw_data)).resize((50,50),Image.ANTIALIAS)
iimage = ImageTk.PhotoImage(img)
Label(self.master, image=iimage).place(x=ex,y=ey)
self.keep.append(iimage)

Why does Tkinter image not show up if created in a function?

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)

Tkinter image labels disappearing when new toplevel opened

Assign a name to your original creation of q_mark and do not create it again

q_mark = Image.open('Image/question_mark.png')
q_mark_re = q_mark.resize((15, 15), Image.ANTIALIAS)
q_mark_new = ImageTk.PhotoImage(q_mark_re, name="qmark")

Use the name everywhere you want to use the image

def manage():
#don't need this
#global q_mark_new

# Defining Login window
admin = Toplevel(root)
admin.title('Login')
admin.focus_force()
.....
# Creating ? icons ~ DON'T DO THIS
#q_mark = Image.open('Image/question_mark.png')
#q_mark_re = q_mark.resize((15, 15), Image.ANTIALIAS)
#q_mark_new = ImageTk.PhotoImage(q_mark_re)

# Making 13 ? icons
q_mark_1 = Label(admin, image="qmark")
q_mark_2 = Label(admin, image="qmark")
q_mark_1.grid(row=2, column=1, padx=(5, 130))
q_mark_2.grid(row=4, column=1, padx=(5, 130))

nametooltip_1 = Pmw.Balloon(root)
nametooltip_2 = Pmw.Balloon(root)
nametooltip_1.bind(q_mark_1, 'Username:\nEnter the given username')
nametooltip_2.bind(q_mark_1, 'Password:\nEnter the given correct password')

Images disappearing in Tkinter

I have solved my problem!
Thanks @FabienAndre and THIS post.
I just realized, that every time i called function, old value of self.photo and self.photo2 variables are cleared and images disappeared.

For solve this trouble, i prepare all images i needed in Class constructor, and every time just use same value in variable.

class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.initImages() #Prepare images
self.master.resizable(width=False, height=False)
self.index = 0
self.grid()

def initImages(self):
self.images = {}
buf = Image.open("Classic.png")
buf = buf.resize((20, 20), Image.ANTIALIAS) #The (250, 250) is (height, width)
self.images['Classic'] = ImageTk.PhotoImage(buf)

buf = Image.open("Jeopardy.png")
buf = buf.resize((20, 20), Image.ANTIALIAS) #The (250, 250) is (height, width)
self.images['Jeopardy'] = ImageTk.PhotoImage(buf)

buf = Image.open("On-site.png")
buf = buf.resize((20, 20), Image.ANTIALIAS) #The (250, 250) is (height, width)
self.images['On-site'] = ImageTk.PhotoImage(buf)

buf = Image.open("On-line.png")
buf = buf.resize((20, 20), Image.ANTIALIAS) #The (250, 250) is (height, width)
self.images['On-line'] = ImageTk.PhotoImage(buf)

def ShowImages(self, frame_in, type_img, place_img):
label = tk.Label(frame_in, image=self.images[type_img])
label.pack(side="right")

label = tk.Label(frame_in, image=self.images[place_img])
label.pack(side="right")

def createWidgets(self, dict_of_data):
frame = tk.Frame(self, relief='sunken')
frame.grid(row=0, column=self.index, sticky="WN")
frame_in = tk.Frame(frame)
frame_in.grid(row=0, sticky="WE", column=self.index)
#some other code here

result of solution

P.S. I know, my english is ridiculous, but i have no practice... Sorry

tkinter key binding causes image to disappear

Your bindings cannot work because the event corresponding to the keypress will be passed instead of the image_number argument in back() and forward().

Also, you are recreating the widgets every time while you should only reconfigure them. So to change the label's image, you can do: my_label.configure(image=<new image>). Also instead of passing image_number as an argument, I would rather use a global variable, so that it will be easier to use the functions in the key bindings:

from tkinter import Tk, Button, Label, DISABLED, NORMAL
from PIL import ImageTk, Image
import board
import time
import neopixel

pixels = neopixel.NeoPixel(board.D18, 30)

root = Tk()
root.configure(bg='black')
root.title("please work")

# define, load, show
my_img1 = ImageTk.PhotoImage(Image.open("1.bmp"))
my_img2 = ImageTk.PhotoImage(Image.open("2.bmp"))
my_img3 = ImageTk.PhotoImage(Image.open("3.bmp"))
my_img4 = ImageTk.PhotoImage(Image.open("4.bmp"))
my_img5 = ImageTk.PhotoImage(Image.open("5.bmp"))
my_img6 = ImageTk.PhotoImage(Image.open("6.bmp"))
my_img7 = ImageTk.PhotoImage(Image.open("7.bmp"))
my_img8 = ImageTk.PhotoImage(Image.open("8.bmp"))

image_list = [my_img1, my_img2, my_img3, my_img4, my_img5, my_img6, my_img7, my_img8]

image_number = 1
# create the label only once
my_label = Label(root, image=image_list[image_number - 1])
my_label.grid(row=0, column=0, columnspan= 3, rowspan=25, padx=440, pady= 5)

def forward(event=None):
global image_number # global variable to keep track of the displayed image
image_number += 1
# change image in label
my_label.configure(image=image_list[image_number - 1])
if image_number == 8:
# last image, disable forward button
button_forward.configure(state=DISABLED)
elif image_number == 2:
# no longer first image, re-enable back button
button_back.configure(state=NORMAL)

pixels.fill((255,0,0))
time.sleep(0.1)
pixels.fill((0,0,0))
time.sleep(0.5)

def back(event=None):
global image_number
image_number -= 1
my_label.configure(image=image_list[image_number - 1])

if image_number == 1:
# first image, disable back button
button_back.configure(state=DISABLED)
elif image_number == 7:
# no longer last image, re-enable forward button
button_forward.configure(state=NORMAL)

pixels.fill((255,0,0))
time.sleep(0.1)
pixels.fill((0,0,0))
time.sleep(0.5)

button_back = Button(root, text="previous", command=back, state=DISABLED)
button_exit = Button(root, text="Exit", command=root.quit)
button_forward = Button(root, text="next", command=forward)

root.bind('<Left>', back)
root.bind('<Right>', forward)

button_back.grid(row=23, column=0)
button_exit.grid(row=23, column=1)
button_forward.grid(row=23, column=2)

root.mainloop()

the garbage collector destroy my image and I can't see it

Try this -

from tkinter import *

root = Tk()
canvas = Canvas(root, bg="yellow")
running =PhotoImage(file='running_1.png')

dino = canvas.create_image(600, 200, image=running)

canvas.pack(fill="both", expand=True)

root.mainloop()

Your code doesn't work because you are referencing the PhotoImage inside the canvas.create_image. You should assign a variable for it and then use image=variable



Related Topics



Leave a reply



Submit