Tkinter Canvas图片无法显示求助(代码无报错但图片不渲染)
Question
I'm learning to implement basic animations with Python and tried inserting an image into a Tkinter Canvas component. The code runs without errors, but the image doesn't show up—though the polygon I created displays just fine. I need to display the image on the Canvas, not in a Label.
Here's my code:
from tkinter import * import time from PIL import * def initiate(): canvas1 = Canvas(root, width=800, height=600) canvas1.pack(expand=YES, fill=BOTH) im = PhotoImage(file='flag.gif', height=100, width=100) canvas1.create_polygon(10, 10, 0, 20, 20, 20, fill='white') print("hi") canvas1.create_image(100, 100, image=im) print('bye') root.update() root = Tk() initiate() root.mainloop()
Answer
This is a super common gotcha with Tkinter's PhotoImage! Let's break down what's happening and how to fix it:
Why the Image Isn't Showing
The problem boils down to Python's garbage collection and how Tkinter handles image references. Your im variable is a local variable inside the initiate() function. Once the function finishes running, Python cleans up local variables—including im. Tkinter's Canvas doesn't keep its own reference to the PhotoImage object, so when im gets deleted, the image data is gone, and nothing displays on the Canvas.
Also, you imported PIL but aren't using it here—since you're working with a GIF (which Tkinter supports natively), that's not the issue right now, but it's worth noting for future image formats like PNG/JPG.
Fixes You Can Try
I recommend the second option below, as it's cleaner and avoids global variables:
1. Make im a Global Variable
By declaring im as a global variable, you ensure it doesn't get cleaned up when the function ends:
from tkinter import * import time from PIL import * def initiate(): global im # Mark as global canvas1 = Canvas(root, width=800, height=600) canvas1.pack(expand=YES, fill=BOTH) im = PhotoImage(file='flag.gif', height=100, width=100) canvas1.create_polygon(10, 10, 0, 20, 20, 20, fill='white') canvas1.create_image(100, 100, image=im) root.update() root = Tk() initiate() root.mainloop()
2. Bind the Image to the Canvas Object
A better approach is to attach the PhotoImage to a property of the Canvas itself. This way, the Canvas's reference to the image keeps it from being garbage collected:
from tkinter import * import time from PIL import * def initiate(): canvas1 = Canvas(root, width=800, height=600) canvas1.pack(expand=YES, fill=BOTH) im = PhotoImage(file='flag.gif', height=100, width=100) canvas1.image = im # Store the image as a canvas attribute canvas1.create_polygon(10, 10, 0, 20, 20, 20, fill='white') canvas1.create_image(100, 100, image=im) root.update() root = Tk() initiate() root.mainloop()
3. Use PIL's ImageTk (For Wider Image Format Support)
If you plan to work with non-GIF images later (like PNG or JPG), use PIL's Image and ImageTk modules. Just remember to still keep a reference to the image object:
from tkinter import * import time from PIL import Image, ImageTk # Import the correct PIL modules def initiate(): canvas1 = Canvas(root, width=800, height=600) canvas1.pack(expand=YES, fill=BOTH) # Open and resize the image with PIL img = Image.open('flag.gif') img = img.resize((100, 100)) im = ImageTk.PhotoImage(img) canvas1.image = im # Keep the reference canvas1.create_polygon(10, 10, 0, 20, 20, 20, fill='white') canvas1.create_image(100, 100, image=im) root.update() root = Tk() initiate() root.mainloop()
内容的提问来源于stack exchange,提问作者Kartik Narang

