Tkinter OptionMenu点击触发PIL图片生成失效问题求助
我开发了一款通过参数生成图片的Tkinter应用,遇到一个问题:当把show(event)作为OptionMenu的command使用时,生成的图片显示为空白矩形;但直接执行图片生成代码却能正常显示。
有问题的完整代码
# 导入库 from tkinter import * from PIL import Image, ImageTk, ImageFont, ImageDraw win=Tk() win.geometry("700x550") # 加载图片文件 thusday=Image.open("E:\спм суд\ЧТ.png") olus=Image.open('E:\спм суд\ОЛУС.png') # 处理函数 def show(event): if clicked.get()=='ОЛУС': Label(win, text='ОЛУСС').pack() img=Image.alpha_composite(olus, thusday) new_width = int(500) new_height = int(new_width * 1080 / 1920) resized_image=img.resize((new_width,new_height), Image.LANCZOS) img = ImageTk.PhotoImage(resized_image) Label(win,image=img).pack(pady=20) Label(win, text=clicked.get()).pack() # 选项列表 cities=[ 'ОЛУС', 'БАРСЕЛОНА', 'СПАВН', 'НЕГОРОД КВАТОСА' ] day=[ 'Четверг', 'Воскресенье' ] # 下拉菜单 clicked=StringVar() clicked.set('город проведения') drop=OptionMenu(win, clicked, *cities, command=show) drop.pack() click=StringVar() click.set('день недели') drop=OptionMenu(win, click, *day) drop.pack() # 按钮(注释掉的) ##Boobs=Button(win, text="GENERATE", command=show).pack()
可正常运行的代码片段
thusday=Image.open("E:\спм суд\ЧТ.png") olus=Image.open('E:\спм суд\ОЛУС.png') img=Image.alpha_composite(olus, thusday) new_width = int(500) new_height = int(new_width * 1080 / 1920) resized_image=img.resize((new_width,new_height), Image.LANCZOS) img = ImageTk.PhotoImage(resized_image) Label(win,image=img).pack(pady=20)
问题原因
问题核心是Python垃圾回收机制:在show函数中,img是局部变量,函数执行完毕后会被垃圾回收器销毁。而Tkinter的PhotoImage对象需要持续存在的引用才能在Label中显示,没有引用时会被回收,导致标签显示空白。直接执行代码时,img是全局变量,不会被立即回收,因此能正常显示。
解决方案
有两种可靠的解决方式:
1. 将img声明为全局变量
修改show函数,在创建PhotoImage前添加global img声明,让变量成为全局引用:
def show(event): global img # 声明为全局变量 if clicked.get()=='ОЛУС': Label(win, text='ОЛУСС').pack() img=Image.alpha_composite(olus, thusday) new_width = int(500) new_height = int(new_width * 1080 / 1920) resized_image=img.resize((new_width,new_height), Image.LANCZOS) img = ImageTk.PhotoImage(resized_image) Label(win,image=img).pack(pady=20) Label(win, text=clicked.get()).pack()
2. 将img绑定到Label对象的属性上
创建Label后,把img赋值给Label的自定义属性,让Label持有对img的引用:
def show(event): if clicked.get()=='ОЛУС': Label(win, text='ОЛУСС').pack() img=Image.alpha_composite(olus, thusday) new_width = int(500) new_height = int(new_width * 1080 / 1920) resized_image=img.resize((new_width,new_height), Image.LANCZOS) img = ImageTk.PhotoImage(resized_image) img_label = Label(win, image=img) img_label.img = img # 绑定引用到Label属性 img_label.pack(pady=20) Label(win, text=clicked.get()).pack()
内容的提问来源于stack exchange,提问作者kakashechka
相关产品推荐
相关产品推荐

