Tkinter报错:image 'pyimage18'不存在,寻求解决方案
Tkinter应用
_tkinter.TclError: image "pyimage18" doesn't exist问题排查与解决 问题描述
基于Tkinter开发的InteL-Trader桌面应用此前运行完全正常,突然触发_tkinter.TclError: image "pyimage18" doesn't exist错误,错误发生在StartPage类加载logo图片到Logo_screen_frame的环节,尝试过网上常见解决方案后问题仍未解决。
相关代码
# 定义应用主框架类,仅包含菜单,所有页面都加载在此框架上 class SeaofBTCapp(Tk): def __init__(self, *args, **kwargs): Tk.__init__(self, *args, **kwargs) # 设置应用图标(需为.ico格式) Tk.iconbitmap(self, default='C:/Users/aurel/Desktop/image.ico') # 设置窗口标题 Tk.wm_title(self, 'InteL-Trader') self.state("zoomed") # 窗口默认最大化 global screen_height global screen_width global one_part global two_part screen_width=self.winfo_screenwidth() screen_height=self.winfo_screenheight() # 屏幕宽度百分比单位 one_part=(16.36/100*screen_width) # 屏幕高度百分比单位 two_part=10/100*screen_height # 应用整体容器框架,位于根窗口之上 Whole_App_Frame=Frame(self, width=screen_width, height=screen_height, bg='gold') Whole_App_Frame.grid(row=0, column=0, columnspan=3) ################################################ # 菜单部分 ################################################ # 在应用容器框架上创建菜单容器 my_menu=Menu(Whole_App_Frame) # 将菜单设置为应用的主菜单 self.config(menu=my_menu) def Stop_bot(): # 触发云端代码停止的函数 pass file_menu=Menu(my_menu) my_menu.add_cascade(label="Home", menu=file_menu) file_menu.add_command(label="Home Page", command=lambda: controller.show_frame(StartPage)) file_menu.add_separator() file_menu.add_command(label="Log out MT5 Account", command=Stop_bot) file_menu.add_separator() file_menu.add_command(label="Exit", command=Whole_App_Frame.quit) # 创建Account菜单选项 Account_menu=Menu(my_menu) my_menu.add_cascade(label="Account", menu=Account_menu) Account_menu.add_command(label="Account Data Page", command=lambda: controller.show_frame(AccountPage)) Account_menu.add_separator() Account_menu.add_command(label="Receipts|Reports|Statements Downloads", command=lambda: controller.show_frame(DownloadsPage)) # 创建Training菜单选项 Training_menu=Menu(my_menu) my_menu.add_cascade(label="Training", menu=Training_menu) Training_menu.add_command(label="How to use Intel Trader", command=lambda: controller.show_frame(HowtoIntel)) Training_menu.add_separator() Training_menu.add_command(label="Forex basics", command=lambda: controller.show_frame(ForexBasics)) Training_menu.add_separator() Training_menu.add_command(label="Advanced Forex analysis and Strategies", command=lambda: controller.show_frame(AdvancedForex)) # 创建Help菜单选项 help_menu=Menu(my_menu) my_menu.add_cascade(label="Help Centre", menu=help_menu) help_menu.add_command(label="Self Help Centre", command=lambda: controller.show_frame(CommunityHelpPage)) help_menu.add_separator() help_menu.add_command(label="Contact US", command=lambda: controller.show_frame(ContactsPage)) help_menu.add_separator() help_menu.add_command(label="Direct Message and Calls", command=lambda: controller.show_frame(CallPage)) # 创建Terms and Conditions菜单选项(无下拉) my_menu.add_command(label="Terms and Conditions", command=lambda: controller.show_frame(TermsPage)) self.frames={} # 注:此处省略了部分页面类,如DownloadsPage等 for F in (StartPage, AccountPage): # 加载所有页面框架,可通过按钮调用切换 frame=F(Whole_App_Frame, self) self.frames[F]=frame frame.grid(row=0, column=0, sticky='nswe') self.show_frame(StartPage) # 默认加载StartPage作为首页 def show_frame(self, cont): # 切换页面的函数,将指定页面置于顶层 frame=self.frames[cont] frame.tkraise() # 定义StartPage页面类 class StartPage(Frame): def __init__(self, parentclass, controller): Frame.__init__(self, parentclass) # 创建第一列框架,使用屏幕宽高的百分比设置尺寸 # Logo和应用名称框架 Logo_screen_frame=LabelFrame(self, width=int(one_part), height=int(two_part), bg='green') Logo_screen_frame.grid(column=0, row=0, padx=2, pady=0, sticky='n', columnspan=2, rowspan=1) # 加载并显示logo图片 logo=Image.open("C:/Users/aurel/trading app/logo1.PNG") logo=logo.resize((int(one_part/3), int(two_part-15))) ph=ImageTk.PhotoImage(logo) label=Label(Logo_screen_frame, image=ph) label.image=ph label.grid(row=0, column=0) ...... app=SeaofBTCapp() app.geometry(str(screen_width)+'x'+str(screen_height)) ani=animation.FuncAnimation(f, animate, interval=1000) app.mainloop()
报错信息
File "c:\Users\aurel\trading app\freshtutorial.py", line 793, in <module> app=SeaofBTCapp() ^^^^^^^^^^^^^ File "c:\Users\aurel\trading app\freshtutorial.py", line 205, in __init__ frame=F(Whole_App_Frame, self) ^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\aurel\trading app\freshtutorial.py", line 234, in __init__ label=Label(Logo_screen_frame, image=ph) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Python312\Lib\tkinter\__init__.py", line 3237, in __init__ Widget.__init__(self, master, 'label', cnf, kw) File "C:\Python312\Lib\tkinter\__init__.py", line 2648, in __init__ self.tk.call( _tkinter.TclError: image "pyimage18" doesn't exist PS C:\Users\aurel\trading app>
针对性解决方案
1. 解决Tk根实例冲突
该错误最常见原因是多个Tk根窗口实例共存,你的代码中animation.FuncAnimation依赖的matplotlib默认会创建独立的Tk根实例,和你自定义的SeaofBTCapp(继承自Tk)冲突。
修改方式:初始化matplotlib时指定TkAgg后端,并绑定到已有的应用窗口:
import matplotlib matplotlib.use('TkAgg') from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg # 在创建FuncAnimation前,将图表绑定到应用窗口 canvas = FigureCanvasTkAgg(f, master=app) canvas.draw() canvas.get_tk_widget().pack(side='top', fill='both', expand=1) ani=animation.FuncAnimation(f, animate, interval=1000)
2. 强化图片引用避免垃圾回收
虽然你已做label.image=ph保留引用,但如果页面框架被意外重建,仍可能丢失引用。将图片引用存储到更持久的控制器实例中:
# 在StartPage的__init__中修改 ph=ImageTk.PhotoImage(logo) label=Label(Logo_screen_frame, image=ph) # 将引用存储到应用控制器实例 controller.logo_photo = ph label.image=ph
3. 规范图片路径写法
使用原始字符串或双反斜杠避免路径转义问题:
# 两种可选写法 logo=Image.open(r"C:\Users\aurel\trading app\logo1.PNG") # 或 logo=Image.open("C:\\Users\\aurel\\trading app\\logo1.PNG")
4. 确保页面框架仅创建一次
避免重复创建页面框架导致图片实例冲突,修改创建逻辑:
self.frames={} for F in (StartPage, AccountPage): if F not in self.frames: frame=F(Whole_App_Frame, self) self.frames[F]=frame frame.grid(row=0, column=0, sticky='nswe')
5. 清理进程缓存
VSCode的Python进程可能残留旧实例导致资源冲突,完全关闭VSCode后重新打开,或在终端杀死所有Python进程后再运行程序。
内容的提问来源于stack exchange,提问作者SUNNETDev
相关产品推荐
相关产品推荐

