连续运行多TK实例报错:_tkinter.TclError及无效命令名求助
问题:连续运行多个CustomTkinter GUI实例时出现TclError错误
问题场景
需要在another.py中循环调用GUI_file.py里的GUI类实例,实现自动连续运行无需人工干预,但启动新实例时触发_tkinter.TclError: can't invoke "destroy" command: application has been destroyed及一系列无效命令名错误,尝试替换self.destroy()为self.quit()等方法未解决。
相关代码
GUI_file.py
import os import cv2 import sys import tkinter as tk import customtkinter from pathlib import Path from PIL import Image, ImageTk from tkinter import Canvas, PhotoImage class GUI(customtkinter.CTk): def __init__(self, id): super().__init__() self.title("Front-end UI") self.geometry(f"{1080}x{720}") # configure grid layout (4x4) self.grid_columnconfigure(1, weight=1) self.grid_columnconfigure((2, 3), weight=0) self.grid_rowconfigure((0, 1, 2), weight=1) self.image_window = customtkinter.CTkFrame(self) self.image_window.grid(row=0, column=1, rowspan=2, padx=5, pady=40, sticky="nsew") self.image_path = os.path.join(Path().absolute() / 'dependent_data', "poo.png") self.org_image = cv2.imread(self.image_path) self.canvas = Canvas(self.image_window, width=1280, height=720, background="white") self.canvas.pack() self.canvas_image = ImageTk.PhotoImage(Image.open(self.image_path)) self.canvas.create_image(625, 350, image=self.canvas_image, anchor="center") # initialize and do something with id self.id = id self.exit = False self.after_id = None # 新增:保存after任务ID self.after_method() def method1(self): self.id += 1 # do something def method2(self, img): cv2.line(img, (self.id, self.id), (self.id, self.id), (0,0,255), 2) self.canvas_image = ImageTk.PhotoImage(Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))) self.canvas.create_image(625, 350, image=self.canvas_image, anchor="center") self.method1() # do something def after_method(self): if self.exit or self.id >= 100: # 新增:取消所有待执行的after任务 if self.after_id: self.after_cancel(self.after_id) # 先退出主循环,再销毁窗口 self.quit() self.destroy() return self.method2(self.org_image.copy()) print(self.id) self.after_id = self.after(10, self.after_method) # 保存after任务ID def method3(self): pass # do something def run_instance(id): # 新增:重置CustomTkinter环境,确保新实例使用独立的Tcl解释器 customtkinter.deactivate() customtkinter.activate() gui = GUI(id) # 修改窗口关闭回调:使用quit而非sys.exit,避免直接终止程序 gui.protocol("WM_DELETE_WINDOW", lambda: gui.quit()) gui.mainloop() # 确保窗口资源完全清理 try: gui.destroy() except: pass print("Finished running instance....")
another.py
# necessary imports from GUI_file import run_instance # 示例ID列表 ids = [10, 20, 30] for id in ids: run_instance(id) # process saved results from instance # pause(5)
错误信息
File "/home/user/project/gui/GUI_file.py", line 803, in update self.destroy() File "/home/user/.local/lib/python3.10/site-packages/customtkinter/windows/ctk_tk.py", line 85, in destroy tkinter.Tk.destroy(self) File "/usr/lib/python3.10/tkinter/__init__.py", line 2341, in destroy self.tk.call('destroy', self._w) _tkinter.TclError: can't invoke "destroy" command: application has been destroyed invalid command name "139702252461440update" while executing "139702252461440update" ("after" script) invalid command name "139702258075584<lambda>" while executing "139702258075584<lambda>" ("after" script) ... invalid command name "139702256197312<lambda>" while executing "139702256197312<lambda>" ("after" script) invalid command name "139702494947200check_dpi_scaling" while executing "139702494947200check_dpi_scaling" ("after" script)
解决方案说明
问题根源:
- 第一个实例调用
destroy后,Tcl解释器被销毁,后续实例尝试使用已失效的解释器资源,触发错误。 after方法注册的任务在窗口销毁后仍可能被触发,导致调用已销毁对象的方法,出现"无效命令名"错误。- 使用
sys.exit作为窗口关闭回调会直接终止整个程序,无法继续循环运行后续实例。
- 第一个实例调用
关键修改点:
- 保存
after任务的ID,在退出前调用self.after_cancel取消所有待执行的异步任务,避免窗口销毁后任务仍被触发。 - 先调用
self.quit()退出主循环,再执行self.destroy()销毁窗口,确保主循环正常结束后再清理资源。 - 在
run_instance中添加customtkinter.deactivate()和customtkinter.activate(),重置CustomTkinter环境,让每个新实例使用独立的Tcl解释器。 - 将窗口关闭回调改为
gui.quit(),避免直接终止程序,保证循环可以继续执行。
- 保存
内容的提问来源于stack exchange,提问作者RoSy8264
相关产品推荐
相关产品推荐

