Tkinter图片仅在对应类调用mainloop()时显示的问题求助
问题分析
你遇到的图片显示异常,核心原因和mainloop()的调用位置无关,而是Python垃圾回收机制导致的图片对象丢失:ImageTk.PhotoImage对象如果没有被持久化引用(比如仅作为局部变量存在),当所在方法执行完毕后,对象会被垃圾回收,从而无法在界面上显示。你之前在不同位置调用mainloop()时,对应类的局部img变量刚好还在作用域内没被回收,所以能临时显示,但这是偶然现象,不是正确解法。
解决方案
只需要给每个图片对象添加持久化引用(绑定为类的实例属性),然后仅调用一次mainloop()就能让所有图片正常显示。修改后的完整代码如下:
import tkinter as tk from tkinter import ttk from PIL import Image, ImageTk class BaseWindow(tk.Tk): def __init__(self): super(BaseWindow, self).__init__() self.geometry("800x700") self.title("test title") frame = ttk.Frame(self) frame.pack() ttk.Label(frame, text="test label").pack() # 将图片保存为实例属性,避免被垃圾回收 self.img = ImageTk.PhotoImage(Image.open("res/male_avatar.png").resize((200, 200))) ttk.Label(frame, image=self.img).pack() frame_parent = ttk.Frame(self) frame_parent.pack() ParentWindow(frame_parent, self) # 仅在这里调用一次mainloop即可 self.mainloop() class ParentWindow(ttk.Frame): def __init__(self, parent, app): super(ParentWindow, self).__init__(parent) self.pack() ttk.Label(self, text="parent label test").pack() # 保存为实例属性 self.img = ImageTk.PhotoImage(Image.open("res/male_avatar.png").resize((200, 200))) ttk.Label(self, image=self.img).pack() ttk.Label(self, text="test label").pack() frame_child = ttk.Frame(self) frame_child.pack() ChildWindow(frame_child, app) class ChildWindow(ttk.Frame): def __init__(self, parent, app): super(ChildWindow, self).__init__(parent) self.pack() ttk.Label(self, text="child label test").pack() # 保存为实例属性 self.img = ImageTk.PhotoImage(Image.open("res/male_avatar.png").resize((200, 200))) ttk.Label(self, image=self.img).pack() ttk.Label(self, text="test label").pack() if __name__ == '__main__': BaseWindow()
关键说明
- 把每个类中的局部变量
img改为实例属性self.img,让图片对象绑定到类实例上,确保Python垃圾回收机制不会销毁它。 - 仅需调用一次
mainloop():可以在BaseWindow的__init__方法末尾调用self.mainloop(),或者在主入口中写BaseWindow().mainloop(),两种方式都能让所有图片正常显示。 - 无需强制传递
app对象给子类(除非有其他业务逻辑需要),图片显示异常的核心是引用丢失,和mainloop的调用位置无关。
内容的提问来源于stack exchange,提问作者Chrishdev
相关产品推荐
相关产品推荐

