添加登录窗口后出现_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()
问题原因
- 多主窗口实例冲突:Tkinter(CustomTkinter基于它)要求一个进程只能有一个主Tk实例。login.py中已经创建了
LoginWindow(继承自ctk.CTk)作为主窗口,在connexion方法里又创建了Main2.Window(同样是ctk.CTk实例),导致Tcl上下文混乱,ImageTk.PhotoImage创建的图片会绑定到第一个主窗口的上下文,新窗口无法找到该图片。 - 模块级代码自动执行: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
相关产品推荐
相关产品推荐

