You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 04:27:09