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

添加登录窗口后出现_tkinter.TclError: image 'pyimage1'不存在求助

问题:登录后启动主程序报_tkinter.TclError: image "pyimage1" doesn't exist

我编写了由main2.py、Appimage.py、spe_widget.py组成的多模块程序,直接运行main2.py时一切功能正常。新增登录窗口(login.py)后,验证通过启动原主程序,程序报错:_tkinter.TclError: image "pyimage1" doesn't exist。以下是可复现错误的最小代码:

Main2.py

import customtkinter as ctk
from spe_widget import *
class Window(ctk.CTk):
    def __init__(self):
        super().__init__()
        self.title('AMC44 Connect')
        self.tabs=ctk.CTkTabview(self,fg_color='#2C3E50',segmented_button_selected_color='#2C3E50')
        self.tabs.add('PROJETS')
        self.tabs.pack(padx=5,pady=5,expand=True,fill=BOTH)
        self.page_projet=ProjetFrame(self.tabs.tab('PROJETS'),self)
        self.page_projet.pack(padx=5,pady=5,expand=True,fill=BOTH)

window = Window()
window.mainloop()

Appimage.py

from PIL import Image,ImageTk,ImageGrab
import os

rep_plan='ressources'

def charge_photo(nom_projet,code_projet,resize,dim=280):
    print(f'le nom du projet selectionné est {nom_projet} et le code est {code_projet}')
    image_path=''
    if nom_projet=='Main_Img':
        image_path='ressources\\Main_img.jpg' 
    elif nom_projet=='00':
        image_path='ressources\\00.jpg'       
    else:
        image_path_by_name=rep_plan + '\\'+ str(nom_projet) + '\\'+ str(nom_projet) + '.jpeg'
        image_path_by_code=rep_plan + '\\'+ str(code_projet) + '\\'+ str(code_projet) + '.jpeg'
        
        if os.path.exists(image_path_by_code):
            image_path=image_path_by_code
            
        elif os.path.exists(image_path_by_name):
            image_path=image_path_by_name
            
        else:
            image_path='ressources\\00.jpg'

    print(f'le chemin de l image est {image_path}')
    if image_path:
        try:
            image=Image.open(image_path)
        except Exception as e:
            print(f'une erreur d ouverture de l image {e}')
            image=None
    #redimensionner l'image
    if resize:
        lo,ho=image.size
        if lo>ho:
            h=dim*ho/lo
            l=dim
        else:
            l=dim*lo/ho
            h=dim
        image=image.resize((int(l),int(h)),Image.LANCZOS) if image else None
    photo=ImageTk.PhotoImage(image) if image else None
   
    return photo

spe_widget.py

import customtkinter as ctk
import tkinter as tk

from Appimage import *

from PIL import Image


class ProjetFrame(ctk.CTkFrame):
    
    def __init__(self,master,winstance,**kwargs):
        super().__init__(master, **kwargs)
        self.master=master
        self.winstance=winstance
        self.loaded_photo=None

        self.image_frame=ctk.CTkFrame(self,border_color='black',border_width=2)
        self.image_frame.grid(row=1,column=0,padx=5,pady=5,sticky='nsew')

        self.of_img_init=charge_photo('00',None,resize=True)
        self.of_img_label=tk.Label(self.image_frame,image=self.of_img_init)
        self.of_img_label.pack(fill="both", expand=True)

login.py

# -*- coding: utf-8 -*-

import customtkinter as ctk


class LoginWindow(ctk.CTk):
    def __init__(self):
        super().__init__()
        self.title('AMC44 Connect')
        self.geometry('+560+400')
        #création du dictionnaire des entré du formulaire
        self.loglabel=ctk.CTkLabel(self,text='login: ')
        self.loglabel.grid(row=0,column=0,padx=5, pady=5)
        
        self.logentry=ctk.CTkEntry(self)
        
        self.logentry.grid(row=0,column=1,padx=5, pady=5)
        self.mdplabel=ctk.CTkLabel(self,text='Mot de passe: ')
        self.mdplabel.grid(row=1,column=0,padx=5, pady=5)
        self.mdpentry=ctk.CTkEntry(self,show='*')
        
        self.mdpentry.grid(row=1,column=1,padx=5, pady=5)
        self.label_info=ctk.CTkLabel(self,text='')
        self.label_info.grid(row=2,column=0,columnspan=2,padx=5, pady=5)
        self.btn=ctk.CTkButton(self,text='connexion',command=self.connexion)
        self.btn.grid(row=3,column=0,columnspan=2,padx=5, pady=5)

    def connexion(self):
     
        test=True
        if test:
            self.label_info.configure(text='connexion réussie')
            self.quit()
            import Main2
            window=Main2.Window()
            window.mainloop()
            
        else:
            self.label_info.configure(text='impossible de se connecter')

logwindow = LoginWindow()
logwindow.mainloop()

问题原因

  1. 多主窗口实例冲突:Tkinter(CustomTkinter基于它)要求一个进程只能有一个主Tk实例。login.py中已经创建了LoginWindow(继承自ctk.CTk)作为主窗口,在connexion方法里又创建了Main2.Window(同样是ctk.CTk实例),导致Tcl上下文混乱,ImageTk.PhotoImage创建的图片会绑定到第一个主窗口的上下文,新窗口无法找到该图片。
  2. 模块级代码自动执行:Main2.py在模块级别直接创建了window实例并调用mainloop(),当login.py导入Main2时,这段代码会自动执行,额外创建了一个未被正确管理的窗口实例,进一步加剧了上下文冲突。

修复方案

1. 修改Main2.py,避免模块导入时自动执行窗口代码

把模块级的窗口创建和主循环放到if __name__ == "__main__":判断中:

import customtkinter as ctk
from spe_widget import *
class Window(ctk.CTk):
    def __init__(self):
        super().__init__()
        self.title('AMC44 Connect')
        self.tabs=ctk.CTkTabview(self,fg_color='#2C3E50',segmented_button_selected_color='#2C3E50')
        self.tabs.add('PROJETS')
        self.tabs.pack(padx=5,pady=5,expand=True,fill=BOTH)
        self.page_projet=ProjetFrame(self.tabs.tab('PROJETS'),self)
        self.page_projet.pack(padx=5,pady=5,expand=True,fill=BOTH)

if __name__ == "__main__":
    window = Window()
    window.mainloop()

2. 修改login.py,彻底销毁登录窗口后启动主程序

用self.destroy()替代self.quit(),确保登录窗口完全关闭,再启动主程序:

# -*- coding: utf-8 -*-

import customtkinter as ctk


class LoginWindow(ctk.CTk):
    def __init__(self):
        super().__init__()
        self.title('AMC44 Connect')
        self.geometry('+560+400')
        #création du dictionnaire des entré du formulaire
        self.loglabel=ctk.CTkLabel(self,text='login: ')
        self.loglabel.grid(row=0,column=0,padx=5, pady=5)
        
        self.logentry=ctk.CTkEntry(self)
        
        self.logentry.grid(row=0,column=1,padx=5, pady=5)
        self.mdplabel=ctk.CTkLabel(self,text='Mot de passe: ')
        self.mdplabel.grid(row=1,column=0,padx=5, pady=5)
        self.mdpentry=ctk.CTkEntry(self,show='*')
        
        self.mdpentry.grid(row=1,column=1,padx=5, pady=5)
        self.label_info=ctk.CTkLabel(self,text='')
        self.label_info.grid(row=2,column=0,columnspan=2,padx=5, pady=5)
        self.btn=ctk.CTkButton(self,text='connexion',command=self.connexion)
        self.btn.grid(row=3,column=0,columnspan=2,padx=5, pady=5)

    def connexion(self):
     
        test=True
        if test:
            self.label_info.configure(text='connexion réussie')
            self.destroy()  # 替换quit为destroy,彻底销毁登录窗口
            from Main2 import Window  # 延迟导入,避免提前执行模块代码
            window=Window()
            window.mainloop()
            
        else:
            self.label_info.configure(text='impossible de se connecter')

if __name__ == "__main__":
    logwindow = LoginWindow()
    logwindow.mainloop()

3. 额外确认:保持图片对象引用

你的spe_widget.py中已经通过self.of_img_init保存了图片对象的引用,这一步没问题,避免了Python垃圾回收机制回收图片对象导致的显示问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 06:42:33