使用Tkinter的withdraw()和deiconify()后程序重启失败问题
问题原因与解决方案
问题描述
用tkinter写的登录/仪表盘程序功能正常,但执行以下操作后出现异常:
- 调用
withdraw()隐藏登录窗口,打开仪表盘窗口 - 调用
deiconify()恢复登录窗口,关闭仪表盘 - 点击登录窗口的关闭按钮(×)后,重新在Visual Studio IDE中运行程序,IDE无法启动程序,必须重启IDE才能恢复。
相关代码
main.py
import tkinter as tk from tkinter import ttk import subprocess import time from tkinter import* from tkinter import messagebox from log import mainDashboardWindow def login(): try: messagebox.showinfo("Success", "Login Successful!") loginWindow.withdraw() mainDashboardWindow(loginWindow,"session") #If successful login, display user dashboard except: messagebox.showerror("Message","Unable To Connect") if __name__ == '__main__': loginWindow = Tk() loginWindow.title('Login') loginWindow.geometry('925x500+300+200') loginWindow.configure(bg="#fff") loginWindow.resizable(False,False) logonBtn = Button(loginWindow,width=43,pady=7,text='Login',bg='#57a1f8',fg='white',cursor='hand2',border=0,command= lambda : login()).place(x=30,y=230) mainloop()
log.py
import tkinter as tk from turtle import color, width from tkinter import* from tkinter import ttk from tkinter import messagebox def logout(dashboardWindow,loginWindow): dashboardWindow.withdraw() loginWindow.deiconify() print("Logout of sap") def mainDashboardWindow(loginWindow,session): dashboardWindow = Tk() dashboardWindow.title('Dashboard') dashboardWindow.geometry('925x500+300+200') dashboardWindow.configure(bg="#fff") dashboardWindow.resizable(False,False) logoutBtn = Button(dashboardWindow,width=19,pady=7,text='Logout',bg='#57a1f8',fg='white',cursor='hand2',border=0,command= lambda : logout(dashboardWindow,loginWindow)) logoutBtn.pack(padx=(0,30),pady=(30,30),side=tk.RIGHT)
问题原因
- 多主窗口冲突:tkinter程序规范是只保留一个主窗口(
Tk()实例),但你的代码在mainDashboardWindow里又新建了一个Tk()实例,导致多个Tcl解释器共存,引发资源管理混乱。 - 进程残留:点击登录窗口关闭按钮时,仪表盘窗口只是被
withdraw()隐藏,没有彻底销毁,导致Tcl解释器进程未完全退出,占用了IDE运行程序所需的资源,后续重新运行时IDE无法绑定新进程,因此启动失败。
解决方案
- 用
Toplevel()创建子窗口:把仪表盘窗口改成主窗口的子窗口,用Toplevel(loginWindow)替代Tk(),确保整个程序只有一个主Tcl解释器实例。 - 彻底销毁窗口:关闭窗口时调用
destroy()方法销毁实例,而非仅隐藏,避免进程残留。
修改后的log.py
import tkinter as tk from tkinter import* from tkinter import ttk from tkinter import messagebox def logout(dashboardWindow,loginWindow): dashboardWindow.destroy() # 销毁仪表盘窗口,而非隐藏 loginWindow.deiconify() print("Logout of sap") def mainDashboardWindow(loginWindow,session): # 使用Toplevel创建子窗口,关联主窗口 dashboardWindow = tk.Toplevel(loginWindow) dashboardWindow.title('Dashboard') dashboardWindow.geometry('925x500+300+200') dashboardWindow.configure(bg="#fff") dashboardWindow.resizable(False,False) # 绑定关闭事件,关闭时销毁窗口并恢复登录窗口 def on_dashboard_close(): dashboardWindow.destroy() loginWindow.deiconify() dashboardWindow.protocol("WM_DELETE_WINDOW", on_dashboard_close) logoutBtn = Button(dashboardWindow,width=19,pady=7,text='Logout',bg='#57a1f8',fg='white',cursor='hand2',border=0,command= lambda : logout(dashboardWindow,loginWindow)) logoutBtn.pack(padx=(0,30),pady=(30,30),side=tk.RIGHT)
修改main.py的主窗口部分
if __name__ == '__main__': loginWindow = Tk() loginWindow.title('Login') loginWindow.geometry('925x500+300+200') loginWindow.configure(bg="#fff") loginWindow.resizable(False,False) # 绑定主窗口关闭事件,确保退出时彻底销毁窗口 def on_main_close(): loginWindow.destroy() loginWindow.protocol("WM_DELETE_WINDOW", on_main_close) logonBtn = Button(loginWindow,width=43,pady=7,text='Login',bg='#57a1f8',fg='white',cursor='hand2',border=0,command= lambda : login()).place(x=30,y=230) mainloop()
内容的提问来源于stack exchange,提问作者marsprogrammer
相关产品推荐
相关产品推荐

