提问人:thomas.winckell 提问时间:5/8/2013 最后编辑:Bryan Oakleythomas.winckell 更新时间:10/11/2023 访问量:93946
为什么在函数中创建的 Tkinter 图像不显示?
Why does Tkinter image not show up if created in a function?
问:
此代码有效:
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()
它向我展示了图像。
现在,这段代码可以编译,但它没有向我显示图像,我不知道为什么,因为它是同一个代码,在一个类中:
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()
答:
121赞
Bryan Oakley
5/8/2013
#1
该变量是一个局部变量,在类实例化后获取垃圾回收。该解决方案涉及保存对照片的引用,例如:photo
self.photo = tkinter.PhotoImage(...)
如果你在谷歌上搜索“tkinter image doesn't display”,第一个结果是这样的:
评论
13赞
Tamas Hegedus
12/27/2020
哇。他们认为这是 tkinter 中的错误吗?他们应该这样做。
4赞
Tamas Hegedus
12/27/2020
我发现了一张非常旧的票,已经关闭了,没有修复:bugs.python.org/issue632323
2赞
Aru
1/20/2021
链接无法正常工作 atm,除了使用“全局”之外,还有其他方法吗?
3赞
Bryan Oakley
1/20/2021
@aru:此示例显示了如何在不使用全局的情况下执行此操作。
10赞
martineau
3/16/2021
@TamasHegedus:我同意这是一个错误,但显然在(目前)将近二十年之后,没有人费心去修复。已经记不清有多少次我看到关于它的问题仍然弹出。
0赞
Gabriel
3/1/2019
#2
只需添加为函数内的第一行即可。global photo
评论
8赞
Aran-Fey
6/20/2019
然后,您创建第二个实例,第一个实例丢失了其映像。祝贺。Test
5赞
Sylvester Kruin - try Codidact
10/29/2021
在课堂上绝对没有必要使用。 负责所有这些。global
self.
9赞
TIRTH SHAH
8/26/2020
#3
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()
只需将全局添加到 img 定义中,它就可以工作了
评论
3赞
Sylvester Kruin - try Codidact
1/8/2022
对于只使用函数的程序来说,这个答案很好,但是如果像 OP 的情况一样,你使用一个类,那么就不是要走的路。global
8赞
Faraaz Kurawle
3/17/2022
#4
问题是 Python 通过称为垃圾回收的过程自动删除对变量的引用。解决方案是保存引用或创建新引用。
以下是方法:
- 用于增加引用计数并保存引用。
self
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()
- 将其保存到列表中以增加引用计数并保存引用。
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()
使用方法 2 时,您可以像我一样创建全局列表,也可以在类中使用列表。两者都行得通。
一些有用的链接:
2赞
Thingamabobs
11/3/2022
#5
根据经验,每当在缩进代码块中创建图像时,都需要保护对该图像的引用。这是因为 python 的自动垃圾回收,当它销毁/离开该帧/页面/缩进的代码块时,它会收集 refcount 为 0 的所有内容。
处理它的规范方法是在全局命名空间的某处有一个图像列表,并将图像引用添加到该列表中。这很方便,但不是很有效,应该用于小型应用程序。
import tkinter as tk
global_image_list = []
global_image_list.append(tk.PhotoImage(file = 'test.png'))
更有效的方法是将属性绑定到您的小部件或类,该小部件或类为您保存该引用,正如 Bryan 在他的回答中提出的那样。如果您这样做或之前分配过,这不会有什么区别。但是,如果您想进一步使用该图像,即使小部件被销毁并垃圾回收,这也可能不是正确的方法。self.image
widget.image
widget = tk.Widget(..
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text='test')
label.image = tk.PhotoImage(file = 'test.png')
label.configure(image=label.image)
评论
effbot.org
PhotoImage
label = Label(image=ImageTk.PhotoImage(Image.fromarray(data)))