CustomTkinter多窗口报错:_tkinter.TclError: image 'pyimage6'不存在
解决CustomTkinter多窗口创建时的图片不存在错误
问题描述
在主窗口appMain中添加按钮打开设置窗口app_settings,点击settingsBtn时触发错误:_tkinter.TclError: image "pyimage6" doesn't exist。使用CustomTkinter构建UI,曾尝试封装类但未解决,推测错误源于创建多个ctk.CTk()实例,同时需要实现主窗口多按钮打开不同新窗口的功能。
错误栈信息:
Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\crist\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1892, in __call__ return self.func(*args) File "C:\Users\crist\PycharmProjects\pythonProject1\venv\lib\site-packages\customtkinter\windows\widgets\ctk_button.py", line 554, in _clicked self._command() File "C:\Users\crist\PycharmProjects\pythonProject1\main.py", line 29, in opensettings go_back_btn = ctk.CTkButton(master=frame_settings, File "C:\Users\crist\PycharmProjects\pythonProject1\venv\lib\site-packages\customtkinter\windows\widgets\ctk_button.py", line 106, in __init__ self._draw() File "C:\Users\crist\PycharmProjects\pythonProject1\venv\lib\site-packages\customtkinter\windows\widgets\ctk_button.py", line 264, in _draw self._update_image() # set image File "C:\Users\crist\PycharmProjects\pythonProject1\venv\lib\site-packages\customtkinter\windows\widgets\ctk_button.py", line 173, in _update_image self._image_label.configure(image=self._image.create_scaled_photo_image(self._get_widget_scaling(), File "C:\Users\crist\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1646, in configure return self._configure('configure', cnf, kw) File "C:\Users\crist\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1636, in _configure self.tk.call(_flatten((self._w, cmd)) + self._options(cnf)) _tkinter.TclError: image "pyimage6" doesn't exist
错误原因
Tkinter(CustomTkinter基于其开发)要求一个程序只能有一个主Tk实例,所有资源(如图片)都绑定到这个实例的Tcl解释器。创建第二个ctk.CTk()会生成独立的Tcl解释器,导致主窗口中加载的图片无法在新窗口中被识别,从而触发图片不存在的错误。
解决方案
使用ctk.CTkToplevel()创建子窗口,它依附于主窗口,共享同一个Tcl解释器,能正常访问主窗口加载的资源。同时移除新窗口中重复的全局设置和多余的事件循环调用。
修改后的完整代码
import customtkinter as ctk import tkinter # 假设这里是你加载图片的代码,示例: # GoBackPic = ctk.CTkImage(light_image=tkinter.PhotoImage(file="go_back.png"), size=(20,20)) # ProfilePic = ctk.CTkImage(light_image=tkinter.PhotoImage(file="profile.png"), size=(20,20)) # PrivacyPic = ctk.CTkImage(light_image=tkinter.PhotoImage(file="privacy.png"), size=(20,20)) # PasswordPic = ctk.CTkImage(light_image=tkinter.PhotoImage(file="password.png"), size=(20,20)) # PreferencesPic = ctk.CTkImage(light_image=tkinter.PhotoImage(file="preferences.png"), size=(20,20)) # SettingsPic = ctk.CTkImage(light_image=tkinter.PhotoImage(file="settings.png"), size=(20,20)) # 主窗口初始化 appMain = ctk.CTk() ctk.set_appearance_mode("dark") ctk.set_default_color_theme("green") appMain.title("FastPals") appMain.geometry("1000x800") def opensettings(): # 使用CTkToplevel创建子窗口,指定主窗口为父容器 app_settings = ctk.CTkToplevel(appMain) app_settings.title("Settings") app_settings.geometry("800x600") # 锁定子窗口,必须关闭才能操作主窗口(可选) app_settings.grab_set() # Frame for setting option with the buttons frame_settings = ctk.CTkFrame(master=app_settings, width=250, height=580, corner_radius=20, bg_color="transparent") frame_settings.pack(padx=20, pady=20) frame_settings.place(relx=0.17, rely=0.5, anchor=tkinter.CENTER) go_back_btn = ctk.CTkButton(master=frame_settings, text="", image=GoBackPic, width=70, height=30) go_back_btn.place(relx=0.2, rely=0.05, anchor=tkinter.CENTER) profile_setting = ctk.CTkButton(master=frame_settings, text="Profile", height=30, image=ProfilePic) profile_setting.place(relx=0.655, rely=0.05, anchor=tkinter.CENTER) privacy_setting = ctk.CTkButton(master=frame_settings, text="Privacy", width=220, height=30, image=PrivacyPic) privacy_setting.place(relx=0.5, rely=0.13, anchor=tkinter.CENTER) password_setting = ctk.CTkButton(master=frame_settings, text="Password", width=220, height=30, image=PasswordPic) password_setting.place(relx=0.5, rely=0.21, anchor=tkinter.CENTER) preferences_setting = ctk.CTkButton(master=frame_settings, text="Preferences", width=220, height=30, image=PreferencesPic) preferences_setting.place(relx=0.5, rely=0.29, anchor=tkinter.CENTER) setting5 = ctk.CTkButton(master=frame_settings, text="Setting 5", width=220, height=30) setting5.place(relx=0.5, rely=0.37, anchor=tkinter.CENTER) setting6 = ctk.CTkButton(master=frame_settings, text="Setting 6", width=220, height=30) setting6.place(relx=0.5, rely=0.45, anchor=tkinter.CENTER) setting7 = ctk.CTkButton(master=frame_settings, text="Setting 7", width=220, height=30) setting7.place(relx=0.5, rely=0.53, anchor=tkinter.CENTER) setting8 = ctk.CTkButton(master=frame_settings, text="Setting 8", width=220, height=30) setting8.place(relx=0.5, rely=0.61, anchor=tkinter.CENTER) # Frame for settings for the chosen option frame_settings_content = ctk.CTkFrame(master=app_settings, width=500, height=580, corner_radius=20, bg_color="transparent") frame_settings_content.pack(padx=20, pady=20) frame_settings_content.place(relx=0.663, rely=0.5, anchor=tkinter.CENTER) # 移除多余的mainloop(),主窗口的mainloop已经处理事件 # 示例:添加另一个按钮打开新窗口 def openprofile(): profile_window = ctk.CTkToplevel(appMain) profile_window.title("Profile") profile_window.geometry("600x400") profile_window.grab_set() # 这里添加个人资料窗口的UI元素 # Settings, Profile and Log out button settingsBtn = ctk.CTkButton(master=appMain, text="Settings", image=SettingsPic, width=30, text_color="black", command=opensettings) settingsBtn.pack(pady=20) profileBtn = ctk.CTkButton(master=appMain, text="Profile", width=100, command=openprofile) profileBtn.pack(pady=10) # 主窗口事件循环 appMain.mainloop()
关键修改点
- 替换窗口创建方式:将
app_settings = ctk.CTk()改为app_settings = ctk.CTkToplevel(appMain),指定主窗口为父容器,确保资源共享。 - 移除重复设置:删除新窗口中的
ctk.set_appearance_mode()和ctk.set_default_color_theme(),这些是全局设置,只需在主窗口初始化时设置一次。 - 删除多余事件循环:新窗口不需要调用
mainloop(),主窗口的appMain.mainloop()已经处理整个程序的事件循环。 - 避免变量名重复:原代码中两个Frame都用了
frame_settings变量名,修改为frame_settings_content避免覆盖。 - 添加窗口锁定(可选):调用
app_settings.grab_set()可以让子窗口获得焦点,必须关闭子窗口才能操作主窗口,提升用户体验。
多窗口扩展方法
要实现多个按钮打开不同新窗口,只需复制类似opensettings()的函数,修改窗口标题、尺寸和内部UI元素,然后将按钮的command绑定到对应的函数即可,如示例中的openprofile()函数和profileBtn按钮。
内容的提问来源于stack exchange,提问作者n00b
相关产品推荐
相关产品推荐

