This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 4 years ago.
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?
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
Related
I'm trying to simply add an image to a tkinter button. I tried everything:
import tkinter as tk
root = tk.Tk()
root.geometry('300x300+300+150')
photo = tk.PhotoImage('home.gif')
btn = tk.Button(root, image = photo, width = 100, height = 100)
btn.image = photo # even with this does not work
btn.pack()
root.mainloop()
I also tried with PIL setting the photo variable equal to ImageTk.PhotoImage(Image.open('home.gif')), I tried easly the open function, the absolute path of the photo (and yes, the photo is inside the same directory of my script), but anything works. The window just pop up with a big button, without image inside.
UPDATE:
I tried with other images, and I noticed that some images are shown while others no. This is because the images with transparent background cause a bug or a problem to tkinter... so, I do not know if there's a way to solve this. On google I find out that some people use canvas but I actually need the image to be inside the button so I do not know how to do.
Please change your code as below
photo = tk.PhotoImage(file='home.gif')
because i changed the above code and it worked....
I am trying to display an image to my GUI, through PhotoImage, however it is telling me that PhotoImage has no "grid" member.
I am using .grid() for all of my other widgets, like labels and buttons, so I can't use .pack(), if that would make a difference anyway. So, how could I display an image to my GUI with grids?
I don't know if code is necessary for this question, but
# it works by getting a random image from a list of files
Label(root, text=f"Enter a number between one and {len(files)}")
self.entry = Entry(root)
self.entry.grid()
Button(root, text="Submit", command=self.getEntry).grid()
Then, getEntry() is:
def getEntry(self):
PhotoImage(name="",
file=f{self.path}\\{self.showImage(self.entry.get())}).grid(row=1)
"""
showImage() just returns the correct file
(e.g: files[index] where index is the input)
"""
NOTE:
grid() is returning NoneValue, which means that your variable 'file' will be NoneValue.
To display an image in tkinter you'll need to do something like:
from PIL import Image, ImageTk
image = Image.open(image_path)
photo = ImageTk.PhotoImage(image)
label = Label(root, image = photo)
label.image = photo
label.grid(row=1)
# label.pack()
NOTE:
The PhotoImage class can read GIF and PGM/PPM images from files:
photo = PhotoImage(file="image.gif")
photo = PhotoImage(file="lenna.pgm")
If you need to work with other file formats, the Python Imaging
Library (PIL) contains classes that lets you load images in over 30
formats, and convert them to Tkinter-compatible image objects:
from PIL import Image, ImageTk
image = Image.open("lenna.jpg")
photo = ImageTk.PhotoImage(image)
You can use a PhotoImage instance everywhere Tkinter accepts an image
object.
An example:
label = Label(image=photo)
label.image = photo # keep a reference!
label.pack()
You must keep a reference to the image object in your Python program, either by storing it in a global variable, or by attaching it to another object.
You have to use a widget that can support images. Typically a label, but button can also configure a button to show an image, as well as add images to text and canvas widgets.
I'm working on a simple tkinter program, and am trying to create a callback function that will take an image (imported using PIL and stored as a class attribute) and draw it on the canvas when the corresponding button is clicked. Each click should create a new Bacteria object, reflected by the creation of a new image on the canvas (in the actual program, the new objects are also appended to an array and used later in the program's execution--the code here is something of a simplification).
The following runs without errors (except for a file-not-found error stemming from the fake file name used for posting) but, unfortunately, no images draw on the canvas when the button is clicked. The code works as intended when the image is imported and stored as an attribute of the MainWindow class--it only seems to fail when imported/stored as an attribute of the Bacteria class.
import tkinter as tk
import random
from PIL import Image
from PIL import ImageTk
class MainWindow(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent, background = "white")
self.pack()
self.canvas_height = 500
self.canvas_width = 1000
self.canvas = tk.Canvas(self, height = self.canvas_height, width = self.canvas_width)
self.canvas.grid(row = 0, column = 0)
self.launch_button = tk.Button(self, text = "Haz clic!", width = 25, command = self.callback)
self.launch_button.grid(row = 1, column = 0, sticky = "W")
def callback(self):
test_bact = Bacteria()
x_pos = random.randint(0,1000)
y_pos = random.randint(0,500)
self.canvas.create_image(x_pos, y_pos, image = test_bact.imageTk)
class Bacteria:
def __init__(self):
self.image = Image.open('testBacterium.png')
self.imageTk = ImageTk.PhotoImage(image=self.image)
root = tk.Tk()
app = MainWindow(root)
app.mainloop()
I'm sort of stumped on this. Can anyone offer any insight on what's going wrong?
From documentation of canvas.create_image() -
create_image(position, **options) [#] Draws an image on the canvas.
image= The image object. This should be a PhotoImage or BitmapImage,
or a compatible object (such as the PIL PhotoImage). The application
must keep a reference to the image object.
(Emphasis mine)
So most probably, either canvas object does not keep a reference to the image itself, or it keeps a weak reference . In either case, in a nutshell what is happening is that after to call canvas.create_image() and the callback() method ends, you are no longer holding any reference to the image object (used in the create_image() method) , and hence its not showing up.
In your case, when you are keeping the reference to the image in Bacteria class , what is happening is -
You are creating the Bacteria object and loading the image and storing there. You are just creating the Bacteria object - test_bact - as a local variable for callback() method.
Then you are using test_bact.imageTk for the image argument to canvas.create_image() method.
Now, the callback() ends, and hence there is no longer any reference to test_bact and so it gets garbage collected. Also , since the only reference to imageTk object was in the Bacteria object, that also gets garbage collected, and hence there are no more references to the image object in your application.
From what you want to achieve, it seems like you should store the bacteria object as an instance variable of MainWindows class.
This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 4 years ago.
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?
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
I'm trying to make a script which will enable me to dynamically update an image object and then post the updated image to a Tkinter Canvas widget. The code here is prototype code, just to get the basics down. The aim here is to put a blue pixel on the image being displayed by the canvas, at the click location.
Something very strange is going on here. I'm using the Wing IDE, and if I run this code through the debugger, with a breakpoint at any line in the woohoo function, and then continue execution after hitting the breakpoint, the code works exactly as expected- putting a blue pixel on the image. If I run the code normally, or through the debugger with no breakpoints, the image is never updated. This leads me to the conclusion that there is some internal wizardry going on which I haven't got much hope of understanding without aid.
I'd really like to know the best way to go about this (or any way, I guess), and if someone could explain to me what's going on under the hood that'd be really cool. Thanks.
from Tkinter import *
from PIL import Image, ImageTk
def woohoo(event):
original.putpixel((event.x,event.y),(0,0,255))
newpic = ImageTk.PhotoImage(original)
c.create_image((0,0),image=newpic, anchor="nw")
main = Tk()
c = Canvas(main, width=300, height=300)
main.geometry("300x300+0+0")
c.pack()
original = Image.open("asc.bmp")
picture = ImageTk.PhotoImage(original)
c.create_image((0,0),image=picture, anchor="nw")
c.bind("<Button-1>", woohoo)
main.mainloop()
My guess is, you're creating a new image in a function. The reference to the image is a local variable. When the function exits, the reference is garbage collected which causes the new image to be destroyed. Most likely, running interactively causes the garbage collector to run differently (perhaps more lazily?)
Changed a little of the other post to work with Python 3+ :
from tkinter import *
def stuff(event):
global picture3
picture3 = PhotoImage(file='picture2.png')
c.itemconfigure(picture2, image = picture3)
main = Tk()
c = Canvas(main, width=300, height=300)
c.pack()
picture = PhotoImage(file='picture1.png')
picture2 = c.create_image(150,150,image=picture)
c.bind("<Button-1>", stuff)
main.mainloop()
try it like this:
from Tkinter import *
from PIL import Image, ImageTk
def woohoo(event):
global picture #
original.putpixel((event.x,event.y),(0,0,255))
picture = ImageTk.PhotoImage(original)#
c.itemconfigure(myimg, image=picture)#
main = Tk()
c = Canvas(main, width=300, height=300)
main.geometry("300x300+0+0")
c.pack()
original = Image.open("asc.bmp")
picture = ImageTk.PhotoImage(original)
myimg = c.create_image((0,0),image=picture, anchor="nw")#
c.bind("<Button-1>", woohoo)
main.mainloop()