You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()

关键修改点

  1. 替换窗口创建方式:将app_settings = ctk.CTk()改为app_settings = ctk.CTkToplevel(appMain),指定主窗口为父容器,确保资源共享。
  2. 移除重复设置:删除新窗口中的ctk.set_appearance_mode()和ctk.set_default_color_theme(),这些是全局设置,只需在主窗口初始化时设置一次。
  3. 删除多余事件循环:新窗口不需要调用mainloop(),主窗口的appMain.mainloop()已经处理整个程序的事件循环。
  4. 避免变量名重复:原代码中两个Frame都用了frame_settings变量名,修改为frame_settings_content避免覆盖。
  5. 添加窗口锁定(可选):调用app_settings.grab_set()可以让子窗口获得焦点,必须关闭子窗口才能操作主窗口,提升用户体验。

多窗口扩展方法

要实现多个按钮打开不同新窗口,只需复制类似opensettings()的函数,修改窗口标题、尺寸和内部UI元素,然后将按钮的command绑定到对应的函数即可,如示例中的openprofile()函数和profileBtn按钮。

内容的提问来源于stack exchange,提问作者n00b

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 02:22:03