如何让Treeview控件中的图片实现永久正常显示?
问题原因
Tkinter 的 PhotoImage 对象存在垃圾回收机制的限制:只要对象没有被Python层面的变量引用,就会被自动回收,哪怕你已经将它绑定到了Treeview控件上,也会出现图片不显示的问题。
你之前直接用self.icon保存无效,是因为每次循环赋值都会覆盖上一次的self.icon引用,之前生成的图标对象没有其他引用就会被回收,最终只会保留最后一个文件的图标,其他都无法显示。
解决方法
在类内部新增一个专门的缓存属性,持久保存所有生成的图标对象,保证它们的引用一直存在不会被回收:
- 在类的
__init__初始化方法中,新增一个列表或字典属性作为图标缓存 - 每次生成新的图标后,将其加入缓存属性中
代码修改示例
第一步:修改初始化方法
class YourClassName: def __init__(self): # 你的原有初始化代码不变,新增下面一行创建缓存 self.icon_cache = [] # 如果要复用同类型图标可以用字典:self.icon_cache = {}
第二步:修改populate方法
def populate(self, path): if os.path.isdir(path): with os.scandir(path) as it: for entry in it: # 提前过滤隐藏文件,减少重复判断 if entry.name.startswith('.'): continue if entry.is_dir(): values1 = [time.asctime(time.localtime(os.path.getmtime(entry.path))), "Folder", os.path.getsize(entry.path)] self.tree.insert("", 'end', text=entry.name, values=values1, open=False, image=self.folderimg) elif entry.is_file(): icon_id = iconHelper.get_icon(path=entry.path, size="small") icon = ImageTk.PhotoImage(icon_id) # 将图标加入缓存,维持引用避免被回收 self.icon_cache.append(icon) values2 = [time.asctime(time.localtime(os.path.getmtime(entry.path))), "File", os.path.getsize(entry.path)] self.tree.insert("", 'end', text=entry.name, values=values2, open=False, image=icon) else: try: os.startfile(path) except OSError: print("File can not be opened")
优化建议
如果需要处理大量文件,相同后缀的文件可以复用图标,避免重复生成浪费内存,可以改用字典做缓存,按文件后缀存储图标:
# 初始化时用字典 self.icon_cache = {} # populate中生成图标部分修改为: ext = os.path.splitext(entry.name)[-1].lower() if ext not in self.icon_cache: icon_id = iconHelper.get_icon(path=entry.path, size="small") icon = ImageTk.PhotoImage(icon_id) self.icon_cache[ext] = icon icon = self.icon_cache[ext]
内容的提问来源于stack exchange,提问作者Yann
相关产品推荐
相关产品推荐

