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

Tkinter登录窗口重复操作后关闭触发_tkinter.TclError异常求助

问题描述

登录功能正常,但注销后重新打开登录窗口,关闭该窗口时虽能正常关闭,但VS Code终端会抛出如下异常:

Exception in Tkinter callback
Traceback (most recent call last):
  File "c:\Users\IMRAN\Desktop\pyapps\blood_donors_admin_dashboard\login.py", line 88, in login
    messagebox.showerror("Error", "Invalid Email/Password!", parent=self.root)
  File "C:\Users\IMRAN\AppData\Local\Programs\Python\Python310\lib\tkinter\messagebox.py", line 98, in showerror
    return _show(title, message, ERROR, OK, **options)
  File "C:\Users\IMRAN\AppData\Local\Programs\Python\Python310\lib\tkinter\messagebox.py", line 76, in _show
    res = Message(**options).show()
  File "C:\Users\IMRAN\AppData\Local\Programs\Python\Python310\lib\tkinter\commondialog.py", line 45, in show
    s = master.tk.call(self.command, *master._options(self.options))
_tkinter.TclError: can't invoke "tk_messageBox" command: application has been destroyed

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\IMRAN\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
    return self.func(*args)
  File "c:\Users\IMRAN\Desktop\pyapps\blood_donors_admin_dashboard\login.py", line 91, in login
    messagebox.showerror("Error", f"Error due to : {str(ex)}", parent=self.root)
  File "C:\Users\IMRAN\AppData\Local\Programs\Python\Python310\lib\tkinter\messagebox.py", line 98, in showerror
    return _show(title, message, ERROR, OK, **options)
  File "C:\Users\IMRAN\AppData\Local\Programs\Python\Python310\lib\tkinter\messagebox.py", line 76, in _show
    res = Message(**options).show()
  File "C:\Users\IMRAN\AppData\Local\Programs\Python\Python310\lib\tkinter\commondialog.py", line 45, in show
    s = master.tk.call(self.command, *master._options(self.options))
_tkinter.TclError: can't invoke "tk_messageBox" command: application has been destroyed

注:第88行是try代码块前的最后一个else分支。

相关login函数代码如下:

def login(self):
    email = self.user.get()
    password = self.passwd.get()
    if email == "" and password == "":
        messagebox.showerror("Error", "Please Enter All The Fields!", parent=self.root)
    elif email == "":
        messagebox.showerror("Error", "Please Enter Email Address!", parent=self.root)
    elif password == "":
        messagebox.showerror("Error", "Please Enter Password!", parent=self.root)
    else:
        ref = db.reference('users')
        data = ref.get()
        
        for key, val in data.items():
             
            self.loguser.update({key:val})
        try:
            for user in self.loguser.values():
                if user['email'] == email and user['password'] == password and user['admin'] == True:
                    self.root.destroy()
                    os.system('python main.py')
            else:
                messagebox.showerror("Error", "Invalid Email/Password!", parent=self.root)
          
        except Exception as ex:
            messagebox.showerror("Error", f"Error due to : {str(ex)}", parent=self.root)
问题分析

核心原因是Tkinter窗口销毁后,仍有代码试图调用依赖该窗口的messagebox:

  1. 登录成功执行self.root.destroy()后,原登录窗口的Tk上下文已失效,但os.system('python main.py')仅启动新进程,原登录进程并未终止,后续循环的else分支会尝试弹出错误框,此时窗口已销毁,触发异常。
  2. 注销后重新打开登录窗口时,可能存在旧的Tk实例残留,关闭窗口时触发未清理的回调,导致在已销毁的应用上下文上调用messagebox。
解决方案

1. 登录成功后立即终止原进程

在self.root.destroy()后添加sys.exit(),确保原登录程序完全退出,不会执行后续代码:

import sys  # 需导入sys模块

def login(self):
    # ... 其他代码 ...
    try:
        found = False
        for user in self.loguser.values():
            if user['email'] == email and user['password'] == password and user['admin'] == True:
                self.root.destroy()
                os.system('python main.py')
                sys.exit()  # 终止当前进程,避免后续代码执行
                found = True
                break
        if not found:
            messagebox.showerror("Error", "Invalid Email/Password!", parent=self.root)
    # ... 其他代码 ...

2. 优化循环逻辑,避免不必要的else分支

把循环的else分支改为显式判断,找到匹配用户后立即跳出循环,减少错误触发:

try:
    found = False
    for user in self.loguser.values():
        if user['email'] == email and user['password'] == password and user['admin'] == True:
            self.root.destroy()
            os.system('python main.py')
            sys.exit()
            found = True
            break
    if not found:
        # 先检查窗口是否存在再弹出消息
        if self.root.winfo_exists():
            messagebox.showerror("Error", "Invalid Email/Password!", parent=self.root)
except Exception as ex:
    if self.root.winfo_exists():
        messagebox.showerror("Error", f"Error due to : {str(ex)}", parent=self.root)

3. 封装安全的消息框函数

避免在已销毁的窗口上弹出消息框,可封装一个检查窗口状态的函数:

def safe_showerror(self, title, message):
    # 检查窗口是否仍存在
    if hasattr(self, 'root') and self.root.winfo_exists():
        messagebox.showerror(title, message, parent=self.root)

然后将所有messagebox.showerror替换为self.safe_showerror。

4. 注销时清理Tk实例

在main.py的注销函数中,确保完全销毁窗口并终止进程,再启动登录程序:

def logout():
    root.destroy()
    os.system('python login.py')
    sys.exit()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:12:32