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
相关产品推荐
相关产品推荐

