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

Tkinter程序偶发运行失败:invalid command name报错求助

问题:Tkinter程序首次运行报错,二次运行完全无法启动

我的Tkinter程序仅首次运行能正常工作,但会抛出以下错误:

invalid command name "4380768768update"
    while executing
"4380768768update"
    ("after" script)
invalid command name "4383331520check_dpi_scaling"
    while executing
"4383331520check_dpi_scaling"
    ("after" script)
invalid command name "4418904256_click_animation"
    while executing
"4418904256_click_animation"
    ("after" script)

二次运行时程序完全无法启动,仍报相同错误,调试工具也无断点信息。我怀疑问题与tkinter、customtkinter的使用方式以及类继承逻辑有关,以下是我的代码:

import random
import string
import csv
from os import urandom
from cryptography.fernet import Fernet

import tkinter as tk
import tkinter.ttk as ttk
import customtkinter

customtkinter.set_appearance_mode("System")  # 模式:system(默认)、light、dark
customtkinter.set_default_color_theme("green")  # 主题:blue(默认)、dark-blue、green

ctk = customtkinter.CTk()  # 创建custom tkinter窗口
ctk.geometry("600x440")
ctk.title("Login")


class Login:
    def __init__(self, ctk):
        super().__init__()
        self.login_win = ctk
        info_frame = customtkinter.CTkLabel(master=ctk)
        info_frame.pack(pady=20, padx=60, fill="both", expand=True)

        # 创建自定义框架
        frame = customtkinter.CTkFrame(master=info_frame, width=320, height=360, corner_radius=15)
        frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER)

        text_label = customtkinter.CTkLabel(master=frame, text="Log into your Account", font=('Century Gothic', 20))
        text_label.place(x=60, y=45)

        self.username = tk.StringVar()
        username_entry = customtkinter.CTkEntry(master=frame, width=220, placeholder_text='Username',
                                                textvariable=self.username)
        username_entry.place(x=50, y=110)

        self.password = tk.StringVar()
        password_entry = customtkinter.CTkEntry(master=frame, width=220, placeholder_text='Password', show="*",
                                                textvariable=self.password)
        password_entry.place(x=50, y=165)

        # 创建自定义按钮
        button1 = customtkinter.CTkButton(master=frame, width=220, text="Login", command=self.logged_in,
                                          corner_radius=6)
        button1.place(x=50, y=240)

    def logged_in(self):
        if self.username.get() == "Hi" and self.password.get() == "Bye":

            login_win.login_win.destroy()  # 销毁当前窗口并创建新窗口

            """
            GeneratePassword类:支持用户生成、复制密码,选择密码强度,存储配置文件。
            """

            class GeneratePassword(ttk.Frame):


            """
            ViewProfile类:支持用户通过列表框查看已生成并保存的配置文件。
            """

            class ViewProfile(ttk.Frame):
...

            """
            Main_view类:承载GeneratePassword和ViewProfile,调用时显示对应内容。
            """

            class Main_view(ttk.Notebook):

                def __init__(self, *args, **kwargs):
                    super().__init__(*args, **kwargs)
                    self.add(GeneratePassword(self),
                             text="Generate Password")  # 创建密码生成标签页
                    self.add(ViewProfile(self), text="View Profiles")  # 创建查看历史密码标签页

            root = tk.Tk()
            root.title("PassX")
            main = Main_view(root)
            main.grid(row=0, column=0)
            root.mainloop()
        else:
            pass


login_win = Login(ctk)
login_win.login_win.mainloop()

问题根源

  • 多主窗口冲突:同时创建customtkinter.CTk()和tk.Tk()两个主窗口,销毁第一个窗口后,CustomTkinter的后台定时任务(如DPI缩放检查、点击动画)找不到对应窗口对象,触发"invalid command name"错误。
  • 类嵌套定义错误:将GeneratePassword等类定义放在logged_in方法内部,导致二次运行时类的上下文混乱,加剧错误。
  • 重复调用mainloop():程序中多次调用主循环,破坏Tkinter的运行逻辑。

修复方案

1. 改用单主窗口+框架切换模式

避免创建多个主窗口,登录成功后销毁登录界面组件,直接在原窗口加载主界面:

import random
import string
import csv
from os import urandom
from cryptography.fernet import Fernet

import tkinter as tk
import tkinter.ttk as ttk
import customtkinter

customtkinter.set_appearance_mode("System")
customtkinter.set_default_color_theme("green")

# 将类移到全局作用域
class GeneratePassword(ttk.Frame):
    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)
        # 实现密码生成功能的UI和逻辑

class ViewProfile(ttk.Frame):
    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)
        # 实现查看配置文件的UI和逻辑

class Main_view(ttk.Notebook):
    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)
        self.add(GeneratePassword(self), text="Generate Password")
        self.add(ViewProfile(self), text="View Profiles")

class Login:
    def __init__(self, root):
        self.root = root
        self.root.geometry("600x440")
        self.root.title("Login")
        self.setup_login_ui()
        
    def setup_login_ui(self):
        info_frame = customtkinter.CTkLabel(master=self.root)
        info_frame.pack(pady=20, padx=60, fill="both", expand=True)

        frame = customtkinter.CTkFrame(master=info_frame, width=320, height=360, corner_radius=15)
        frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER)

        text_label = customtkinter.CTkLabel(master=frame, text="Log into your Account", font=('Century Gothic', 20))
        text_label.place(x=60, y=45)

        self.username = tk.StringVar()
        username_entry = customtkinter.CTkEntry(master=frame, width=220, placeholder_text='Username',
                                                textvariable=self.username)
        username_entry.place(x=50, y=110)

        self.password = tk.StringVar()
        password_entry = customtkinter.CTkEntry(master=frame, width=220, placeholder_text='Password', show="*",
                                                textvariable=self.password)
        password_entry.place(x=50, y=165)

        button1 = customtkinter.CTkButton(master=frame, width=220, text="Login", command=self.logged_in,
                                          corner_radius=6)
        button1.place(x=50, y=240)
        
    def logged_in(self):
        if self.username.get() == "Hi" and self.password.get() == "Bye":
            # 销毁登录界面所有组件
            for widget in self.root.winfo_children():
                widget.destroy()
            
            # 加载主界面
            self.root.title("PassX")
            main = Main_view(self.root)
            main.pack(fill="both", expand=True)

if __name__ == "__main__":
    root = customtkinter.CTk()
    app = Login(root)
    root.mainloop()

2. 关键修复点说明

  • 全局类定义:把GeneratePassword等类从logged_in方法内移到全局范围,避免嵌套定义的上下文问题。
  • 单主窗口:全程使用customtkinter.CTk()作为唯一主窗口,不混合tk.Tk(),保证CustomTkinter组件的兼容性。
  • 单一mainloop():仅在程序入口调用一次mainloop(),避免重复触发主循环。

3. 备选方案:销毁窗口前清理定时任务

如果必须销毁原窗口再创建新窗口,需提前取消所有CustomTkinter的定时任务:

# 在销毁窗口前添加以下代码
for id in self.root.tk.call('after', 'info'):
    self.root.after_cancel(id)
self.root.destroy()

但此方式不如单窗口切换框架可靠,优先推荐前者。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 19:54:58