Tkinter仅最后创建的Label显示图片问题求助
问题描述
以下是一段用于展示水果图片与价格的Tkinter代码:
import tkinter as tk from PIL import ImageTk, Image from scripts.values import readFruitPrices from scripts.stock import getCurrentFruits root = tk.Tk() root.geometry("500x500") root.iconbitmap("assets/kitsune.ico") root.title("Blox Fruits") def fruitLabel(root, fruitName="rocket", width = 75, height = 75, relief = "ridge"): global fruitIcon frame = tk.Frame(root, borderwidth=2, relief=relief) fruitIcon = ImageTk.PhotoImage(Image.open("assets/"+fruitName+".png").resize( (width,height) )) fruitPrice = readFruitPrices()[fruitName] fruitPriceString = "$"+f'{fruitPrice:,}' #puts commas as the thousands seperator picLabel = tk.Label(frame, image=fruitIcon) label = tk.Label(frame, text=fruitName+"\n"+fruitPriceString) picLabel.pack() label.pack() return frame cFruits = getCurrentFruits() fruitLabels = list() for fruit in cFruits: fruitLabels.append(fruitLabel(root, fruit.name.lower())) for i, l in enumerate(fruitLabels): l.grid(row=0,column=i) root.mainloop()
其中getCurrentFruits()会返回包含名称和价格的水果列表。实际运行时仅最后一个Label能显示图片,其余均为空白,已确认所有水果图片文件存在且命名正确,无论水果数量多少,仅最后一个显示图片。
问题原因
核心问题出在**全局变量fruitIcon**和Tkinter的内存管理机制:
- 每次调用
fruitLabel函数时,全局变量fruitIcon都会被新的ImageTk.PhotoImage对象覆盖,之前的图片对象失去了唯一的引用。 - Tkinter的
PhotoImage对象如果没有被任何Python对象持有引用,会被Python的垃圾回收机制自动销毁,导致对应的Label无法显示图片。最后一个图片因为是最后一次赋值,fruitIcon还持有它的引用,所以能正常显示。
解决方案
只需要给每个PhotoImage对象保留独立的引用,避免被覆盖和回收,有两种简单的实现方式:
方式一:将图片绑定到Label对象的属性
修改fruitLabel函数,去掉全局变量,把图片对象绑定到对应的Label上:
def fruitLabel(root, fruitName="rocket", width = 75, height = 75, relief = "ridge"): frame = tk.Frame(root, borderwidth=2, relief=relief) fruitIcon = ImageTk.PhotoImage(Image.open("assets/"+fruitName+".png").resize( (width,height) )) fruitPrice = readFruitPrices()[fruitName] fruitPriceString = "$"+f'{fruitPrice:,}' picLabel = tk.Label(frame, image=fruitIcon) # 将图片对象绑定到Label的属性上,保留引用 picLabel.image = fruitIcon label = tk.Label(frame, text=fruitName+"\n"+fruitPriceString) picLabel.pack() label.pack() return frame
方式二:用列表存储所有图片引用
在函数外维护一个列表,保存每个图片对象的引用:
# 在函数外定义一个列表保存图片引用 image_references = [] def fruitLabel(root, fruitName="rocket", width = 75, height = 75, relief = "ridge"): frame = tk.Frame(root, borderwidth=2, relief=relief) fruitIcon = ImageTk.PhotoImage(Image.open("assets/"+fruitName+".png").resize( (width,height) )) # 将图片对象添加到列表中,保留引用 image_references.append(fruitIcon) fruitPrice = readFruitPrices()[fruitName] fruitPriceString = "$"+f'{fruitPrice:,}' picLabel = tk.Label(frame, image=fruitIcon) label = tk.Label(frame, text=fruitName+"\n"+fruitPriceString) picLabel.pack() label.pack() return frame
内容的提问来源于stack exchange,提问作者Mews
相关产品推荐
相关产品推荐

