Tkinter循环生成Button时image属性失效、宽高属性不生效问题
问题原因梳理
1. 按钮配置image后灰化、无法点击、不显示图片
该问题由Tkinter的图片引用机制导致:Tkinter不会主动持有PhotoImage对象的引用,函数执行完毕后,局部作用域内的ButtonPhoto变量会被销毁,对应的图片资源被垃圾回收,按钮无法找到关联的图片资源就会出现灰化失效的情况。你仅将Button组件存入了全局列表,没有同步存储对应的图片对象,无法避免回收逻辑。
2. 配置text属性时width、height不生效
Tkinter的Button组件宽高单位会随内容类型变化:
- text模式下,width、height的单位是字符宽度/行数,不是像素,你设置的110、85这类数值对应成百个字符宽度,要么超出容器被挤压,要么显示异常看起来不生效
- 只有image模式下,width、height的单位才是像素
3. 用Image.open加载图片报错的原因
你用错了加载方法:原生tkinter.PhotoImage的file参数仅支持传入文件路径,不能直接传入PIL的Image对象。要兼容更多图片格式、支持PIL处理图片,应该用ImageTk.PhotoImage()包裹PIL的Image对象,而非将Image对象传给原生PhotoImage的file参数,你错误传入Image对象后,程序会把对象的toString结果当成路径去查找文件,自然会提示路径不存在。
修复方案
你需要新增一个全局的图片缓存列表,用来持有所有按钮的图片引用,避免被垃圾回收,同时修正PIL图片的加载逻辑,示例代码如下:
from tkinter import * from tkinter import filedialog as fd from tkinter.messagebox import showinfo from PIL import Image, ImageTk # 新增全局图片缓存列表,和ImageButtonList同级定义 ButtonPhotoCache = [] ImageButtonList = [] def OnSomeClick(): # ---其他原有代码不变--- if Orientation == 1: for i in range(len(Ordered_xCoord)): InitButtonPhoto = '{}.png'.format(i) # 若需要用PIL处理图片(缩放、转格式等)用下面的写法,替代原生PhotoImage # pil_img = Image.open(InitButtonPhoto).resize((110,85)) # 可直接缩放到按钮需要的尺寸 # ButtonPhoto = ImageTk.PhotoImage(pil_img) ButtonPhoto = PhotoImage(file=InitButtonPhoto) # 图片存入全局缓存,避免被回收 ButtonPhotoCache.append(ButtonPhoto) btn = Button(action_window, command=Command, bd=3, width=110, height=85, image=ButtonPhoto) ImageButtonList.append(btn) btn.grid(row=Ordered_yCoord[i], column=Ordered_xCoord[i]) else: for i in range(len(Ordered_xCoord)): InitButtonPhoto = '{}.png'.format(i) ButtonPhoto = PhotoImage(file=InitButtonPhoto) ButtonPhotoCache.append(ButtonPhoto) btn = Button(action_window, image=ButtonPhoto, command=Command, bd=3, width=85, height=110) ImageButtonList.append(btn) btn.grid(row=Ordered_yCoord[i], column=Ordered_xCoord[i])
如果需要在text模式下使用像素级的宽高,可以给Button加一张1x1的透明占位图,设置compound='center'让文字显示在图片上方,此时宽高单位就会变成像素。
内容的提问来源于stack exchange,提问作者Henry
相关产品推荐
相关产品推荐

