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:
- 登录成功执行
self.root.destroy()后,原登录窗口的Tk上下文已失效,但os.system('python main.py')仅启动新进程,原登录进程并未终止,后续循环的else分支会尝试弹出错误框,此时窗口已销毁,触发异常。 - 注销后重新打开登录窗口时,可能存在旧的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
相关产品推荐
相关产品推荐

