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

Tkinter中placesmth函数无法显示指定图片问题求助

问题:Tkinter中placesmth函数生成空白标签而非指定图片

我编写了一个小型Tkinter程序,当选择元素并放置时,placesmth函数仅生成空白标签而非指定的图片。以下是完整代码及该函数的具体实现,恳请告知问题原因及解决方法。

完整代码

# Imports

import tkinter as tk
from PIL import ImageTk, Image

# Vars

mainbgc = "#2c2c2c"
label_mainleftc = "#3c3c3c"
label_maintopc = "#4c4c4c"
label_leftsel = "#5c5c5c"

# Tk

root = tk.Tk()
root.title("Zilius")
root.iconbitmap("zilius128.ico")
screen_width = round(root.winfo_screenwidth() / 2)
screen_height = round(root.winfo_screenheight() / 2)
root.geometry(f"{screen_width}x{screen_height}")
root.configure(bg=mainbgc)


cable = False
computer = False
switch = False
count = 0

def placesmth(x, y, img):
    image_png_placesmth = Image.open(img).resize((60, 60))
    photo_png_placesmth = ImageTk.PhotoImage(image=image_png_placesmth)
    addsmth = tk.Label(root, image=photo_png_placesmth)
    addsmth.place(x=x, y=y)

def getorigin(eventorigin):
    global x, y
    x = eventorigin.x
    y = eventorigin.y
    if x >= 75 and y >= 45:
        if computer == True:
            placesmth(x, y, "png_leftcomputer.png")
        if cable == True:
            print(f"Cable {x, y}")
        if switch == True:
            placesmth(x, y, "png_leftswitch.png")

root.bind("<Button 1>", getorigin)

def button_run():
    print("Runned")

def changesel_cable():
    global computer
    global switch
    button_png_leftcable.configure(bg=label_leftsel)
    button_png_leftswitch.configure(bg=label_mainleftc)
    button_png_leftcomputer.configure(bg=label_mainleftc)
    computer = False
    switch = False

def changesel_computer():
    global cable
    global switch
    button_png_leftcomputer.configure(bg=label_leftsel)
    button_png_leftswitch.configure(bg=label_mainleftc)
    button_png_leftcable.configure(bg=label_mainleftc)
    switch = False
    cable = False

def changesel_switch():
    global cable
    global computer
    button_png_leftswitch.configure(bg=label_leftsel)
    button_png_leftcomputer.configure(bg=label_mainleftc)
    button_png_leftcable.configure(bg=label_mainleftc)
    computer = False
    cable = False

def button_leftcable():
    global cable
    cable = True
    changesel_cable()

def button_leftcomputer():
    global computer
    computer = True
    changesel_computer()

def button_leftswitch():
    global switch
    switch = True
    changesel_switch()


label_mainleft = tk.Label(bg=label_mainleftc)
label_mainleft.place(x=0, y=0, height=int(round(root.winfo_screenheight())), width=75)
label_maintop = tk.Label(bg=label_maintopc)
label_maintop.place(x=0, y=0, width=int(round(root.winfo_screenwidth())), height=40)

image_png_runbutton = Image.open("png_runbutton.png").resize((30, 30))
photo_png_runbutton = ImageTk.PhotoImage(image=image_png_runbutton)
button_png_runbutton = tk.Button(root, image=photo_png_runbutton, bg=label_maintopc, activebackground=label_maintopc, borderwidth=-1, command=button_run)
button_png_runbutton.place(x=50,y=4)

image_png_leftcable = Image.open("png_leftcable.png").resize((60, 60))
photo_png_leftcable = ImageTk.PhotoImage(image=image_png_leftcable)
button_png_leftcable = tk.Button(root, image=photo_png_leftcable, bg=label_mainleftc, activebackground=label_mainleftc, borderwidth=-1, command=button_leftcable)
button_png_leftcable.place(x=5,y=40)

image_png_leftcomputer = Image.open("png_leftcomputer.png").resize((60, 60))
photo_png_leftcomputer = ImageTk.PhotoImage(image=image_png_leftcomputer)
button_png_leftcomputer = tk.Button(root, image=photo_png_leftcomputer, bg=label_mainleftc, activebackground=label_mainleftc, borderwidth=-1, command=button_leftcomputer)
button_png_leftcomputer.place(x=5,y=105)

image_png_leftswitch = Image.open("png_leftswitch.png").resize((60, 60))
photo_png_leftswitch = ImageTk.PhotoImage(image=image_png_leftswitch)
button_png_leftswitch = tk.Button(root, image=photo_png_leftswitch, bg=label_mainleftc, activebackground=label_mainleftc, borderwidth=-1, command=button_leftswitch)
button_png_leftswitch.place(x=5,y=170)

root.mainloop()

问题函数

def placesmth(x, y, img):
    image_png_placesmth = Image.open(img).resize((60, 60))
    photo_png_placesmth = ImageTk.PhotoImage(image=image_png_placesmth)
    addsmth = tk.Label(root, image=photo_png_placesmth)
    addsmth.place(x=x, y=y)

问题原因

这是Tkinter的典型问题:ImageTk.PhotoImage对象被Python垃圾回收机制回收。在placesmth函数中,photo_png_placesmth是局部变量,函数执行完毕后,该对象没有任何外部引用,会被Python自动回收,导致Label失去图片源,显示空白。

解决方法

有两种可靠的解决方案,推荐第一种:

方案1:将图片引用绑定到Label对象上

给生成的Label添加一个属性,保存对应的PhotoImage对象,只要Label存在,图片引用就不会被回收。修改后的placesmth函数如下:

def placesmth(x, y, img):
    image_png_placesmth = Image.open(img).resize((60, 60))
    photo_png_placesmth = ImageTk.PhotoImage(image=image_png_placesmth)
    addsmth = tk.Label(root, image=photo_png_placesmth)
    # 保存图片引用,避免被垃圾回收
    addsmth.image = photo_png_placesmth
    addsmth.place(x=x, y=y)

方案2:用全局列表保存所有图片引用

在全局作用域定义一个列表,将每个生成的PhotoImage对象添加进去,通过全局引用阻止回收。适合需要批量管理图片的场景:

# 在全局变量区域添加
placed_images = []

def placesmth(x, y, img):
    image_png_placesmth = Image.open(img).resize((60, 60))
    photo_png_placesmth = ImageTk.PhotoImage(image=image_png_placesmth)
    # 添加到全局列表保存引用
    placed_images.append(photo_png_placesmth)
    addsmth = tk.Label(root, image=photo_png_placesmth)
    addsmth.place(x=x, y=y)

内容的提问来源于stack exchange,提问作者yLetzter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:09:16