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

Tkinter登录验证通过后切换窗口的正确实现方式及相关报错解决问询

Fixing Tkinter Window Switch Error: Invalid Command Name from "after" Script

Let's break down what's causing your error and how to fix it while keeping your desired structure.

Why the Error Happens

When you call menuPrincipal.destroy() on your root login window, it immediately removes the window from memory—but any pending after() callbacks (like periodic updates or timers) tied to that window will still try to run. Since the window no longer exists, Tkinter throws the "invalid command name" error you're seeing. Additionally, your open() function wasn't starting the mainloop for the new window, which would have caused it to close immediately otherwise.

This follows Tkinter best practices (avoiding multiple Tk() instances) while letting you keep most of your code structure:

Step 1: Update main.py Validation Logic

Instead of destroying the login window right away, hide it with withdraw() and pass it to your open() function:

for i in c:
    if user == i['USUARIO'] and contra == i['CONTRASEÑA']:
        messagebox.showinfo(title='Correcto', message='Usuario y Contraseña Correctos')
        # Hide login window instead of destroying it
        menuPrincipal.withdraw()
        # Pass the login window to the open function
        mainformuser.open(menuPrincipal)
        break
else:
    messagebox.showerror(title=None, message='Usuario o Contraseña Incorrectos')

Step 2: Modify mainformuser.py to Use Toplevel()

Change your open() function to create a Toplevel window (attached to the existing root) instead of a new Tk() instance, and add cleanup logic:

from tkinter import *
from time import *
from PIL import ImageTk, Image
import sqlite3
from tkinter import messagebox

def open(parent):
    # Use Toplevel instead of Tk to attach to the login window's root
    top = Toplevel(parent)
    top.title('Menú Principal')
    top.configure(background='black')
    top.resizable(True, True)
    app_width = 1300
    app_height = 777
    screen_width = top.winfo_screenwidth()
    scree_height = top.winfo_screenheight()
    x = (screen_width/2) - (app_width/2)
    y = (scree_height/2.2) - (app_height/2)
    top.geometry(f'{app_width}x{app_height}+{int(x)}+{int(y)}')
    
    # Clean up both windows when the main menu is closed
    def on_menu_close():
        top.destroy()
        parent.destroy()
    
    top.protocol("WM_DELETE_WINDOW", on_menu_close)
    
    # Add your additional functionality here

Solution 2: Keep Using Tk() for the New Window

If you must retain the Tk() instance in your open() function, adjust the flow to avoid immediate destruction of the login window:

Step 1: Update main.py

for i in c:
    if user == i['USUARIO'] and contra == i['CONTRASEÑA']:
        messagebox.showinfo(title='Correcto', message='Usuario y Contraseña Correctos')
        # Hide login window to prevent after callback errors
        menuPrincipal.withdraw()
        # Run the new window's mainloop
        mainformuser.open()
        # Destroy login window only after new window closes
        menuPrincipal.destroy()
        break
else:
    messagebox.showerror(title=None, message='Usuario o Contraseña Incorrectos')

Step 2: Add mainloop() to mainformuser.py

Ensure your new window stays open by starting its mainloop:

def open():
    top = Tk()
    top.title('Menú Principal')
    top.configure(background='black')
    top.resizable(True, True)
    app_width = 1300
    app_height = 777
    screen_width = top.winfo_screenwidth()
    scree_height = top.winfo_screenheight()
    x = (screen_width/2) - (app_width/2)
    y = (scree_height/2.2) - (app_height/2)
    top.geometry(f'{app_width}x{app_height}+{int(x)}+{int(y)}')
    
    # Start the mainloop for the new window
    top.mainloop()

Key Takeaways

  • Avoid multiple Tk() instances: Using Toplevel() is the standard way to create secondary windows in Tkinter, as it shares the existing event loop and avoids unexpected behavior.
  • Delay destroying the root window: Using withdraw() instead of destroy() immediately prevents pending after() callbacks from failing, since the window still exists in memory until you explicitly destroy it later.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 08:14:10