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

销毁TtkBootstrap登录窗口时出现bgerror错误及程序冻结求助

解决tkinter/ttkbootstrap登录窗口销毁后主窗口报错冻结问题

我开发了一款简单的Python应用,流程为:先打开名为root的登录窗口,用户验证凭据通过后,关闭登录窗口并打开名为MainWindow的主窗口。但执行该操作时,程序总会出现以下错误并冻结:

bgerror failed to handle background error.
    Original error: can't invoke "event" command: application has been destroyed
    Error in bgerror: can't invoke "tk" command: application has been destroyed

原相关代码

import tkinter as tk
from tkinter import filedialog
import ttkbootstrap as tb
from ttkbootstrap.dialogs import Messagebox

# login check
def login_check(username, password):
    if username == "a" and password == "p":
        return True
    else:
        return False

# login function
def on_login_click():
    username = ent_codice_utente.get()
    password = ent_password.get()

    if login_check(username, password):
        root.destroy()
        MainWindow()
                        
    else:
        err_credential = Messagebox.show_error('Invalid credential', parent=root)

def MainWindow():
    MainWindow = tb.Window(title='GESCON', themename='superhero')
    MainWindow.geometry('1366x768')

    MainWindow.columnconfigure(0, weight=1)
    MainWindow.rowconfigure(0, weight=1) 
    MainWindow.rowconfigure(1, weight=4)

    frm_filtri = tb.LabelFrame(MainWindow, text="Filter", borderwidth=2)
    frm_filtri.columnconfigure(0, weight=10)
    frm_filtri.columnconfigure(1, weight=10)
    frm_filtri.columnconfigure(2, weight=10)
    frm_filtri.rowconfigure(0, weight=10)
    frm_filtri.rowconfigure(1, weight=10)
    frm_filtri.rowconfigure(2, weight=10)
    frm_griglia = tb.LabelFrame(MainWindow, text='Result', borderwidth=2)

    frm_filtri.grid(column=0, row=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=5, pady=5)
    frm_griglia.grid(column=0, row=1, sticky=(tk.W, tk.E, tk.N, tk.S), padx=5, pady=5)
    
    btn_elabora = tb.Button(frm_filtri, text='Search')
    btn_elabora.grid(column=3, row=2, padx=50, pady=5)
    
    menubar = tb.Menu(MainWindow)
    MainWindow.config(menu=menubar)
    menu_file = tb.Menu(menubar, tearoff=0) 
    menu_help = tb.Menu(menubar, tearoff=0)

    menubar.add_cascade(label='File', menu=menu_file)
    menubar.add_cascade(label='Help', menu=menu_help)

    menu_anagrafiche = tb.Menu(menu_file, tearoff=0)
    menu_file.add_cascade(label='Anagrafiche', menu=menu_anagrafiche)
    menu_file.add_separator()
    menu_file.add_command(label='Import file')
    menu_file.add_separator()
    menu_file.add_command(label='Exit')

    menu_help.add_command(label='Info')
    
#Login window

root = tb.Window(title='Login', themename='superhero')
root.geometry('500x300')

lbl_codice_utente = tb.Label(root, text="User:")
ent_codice_utente = tb.Entry(root)

lbl_password = tb.Label(root, text="Password:")
ent_password = tb.Entry(root, show="*")

btn_login = tb.Button(root, text="Login", bootstyle='success, outline', command=on_login_click)
btn_exit = tb.Button(root, text="Exit", bootstyle='danger, outline', command = lambda:root.destroy())

lbl_codice_utente.grid(padx=10, pady=10, column=0, row=0, sticky='e')
ent_codice_utente.grid(pady=5, column=1, row=0, sticky='w')
lbl_password.grid(padx=10, pady=10, column=0, row=1, sticky='e')
ent_password.grid(pady=5, column=1, row=1, sticky='w')
btn_login.grid(pady=20, column=0, row=3)
btn_exit.grid(pady=20, column=1, row=3)

root.mainloop()

问题原因

销毁root窗口时,ttkbootstrap底层关联的tk主对象被销毁,但原mainloop仍在运行,后续创建新的tb.Window会导致事件处理逻辑混乱,触发报错。

解决方案

方案1:隐藏登录窗口而非直接销毁

修改登录成功后的逻辑,先隐藏登录窗口,启动主窗口循环,待主窗口关闭后再销毁登录窗口:

def on_login_click():
    username = ent_codice_utente.get()
    password = ent_password.get()

    if login_check(username, password):
        root.withdraw()  # 隐藏登录窗口
        main_win = MainWindow()
        main_win.mainloop()
        root.destroy()  # 主窗口关闭后销毁登录窗口
    else:
        err_credential = Messagebox.show_error('Invalid credential', parent=root)

同时修改MainWindow函数,避免变量名覆盖函数本身:

def MainWindow():
    main_win = tb.Window(title='GESCON', themename='superhero')
    main_win.geometry('1366x768')
    # 其余代码保持不变,将所有MainWindow替换为main_win
    ...

方案2:使用单主窗口切换框架(更推荐)

不销毁主窗口,将登录界面和主界面封装为不同的Frame,登录成功后切换显示框架,这是tkinter界面切换的标准稳定做法:

import tkinter as tk
from tkinter import filedialog
import ttkbootstrap as tb
from ttkbootstrap.dialogs import Messagebox

# login check
def login_check(username, password):
    return username == "a" and password == "p"

def show_main_frame():
    login_frame.pack_forget()
    main_frame.pack(fill=tk.BOTH, expand=True)

def on_login_click():
    username = ent_codice_utente.get()
    password = ent_password.get()
    if login_check(username, password):
        show_main_frame()
    else:
        Messagebox.show_error('Invalid credential', parent=root)

# 主窗口初始化
root = tb.Window(title='GESCON', themename='superhero')
root.geometry('1366x768')

# 登录框架
login_frame = tb.Frame(root)
login_frame.pack(expand=True)

lbl_codice_utente = tb.Label(login_frame, text="User:")
ent_codice_utente = tb.Entry(login_frame)
lbl_password = tb.Label(login_frame, text="Password:")
ent_password = tb.Entry(login_frame, show="*")
btn_login = tb.Button(login_frame, text="Login", bootstyle='success, outline', command=on_login_click)
btn_exit = tb.Button(login_frame, text="Exit", bootstyle='danger, outline', command=root.destroy)

# 登录界面布局
lbl_codice_utente.grid(padx=10, pady=10, column=0, row=0, sticky='e')
ent_codice_utente.grid(pady=5, column=1, row=0, sticky='w')
lbl_password.grid(padx=10, pady=10, column=0, row=1, sticky='e')
ent_password.grid(pady=5, column=1, row=1, sticky='w')
btn_login.grid(pady=20, column=0, row=3)
btn_exit.grid(pady=20, column=1, row=3)

# 主界面框架
main_frame = tb.Frame(root)

frm_filtri = tb.LabelFrame(main_frame, text="Filter", borderwidth=2)
frm_filtri.columnconfigure(0, weight=10)
frm_filtri.columnconfigure(1, weight=10)
frm_filtri.columnconfigure(2, weight=10)
frm_filtri.rowconfigure(0, weight=10)
frm_filtri.rowconfigure(1, weight=10)
frm_filtri.rowconfigure(2, weight=10)
frm_griglia = tb.LabelFrame(main_frame, text='Result', borderwidth=2)

frm_filtri.grid(column=0, row=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=5, pady=5)
frm_griglia.grid(column=0, row=1, sticky=(tk.W, tk.E, tk.N, tk.S), padx=5, pady=5)

btn_elabora = tb.Button(frm_filtri, text='Search')
btn_elabora.grid(column=3, row=2, padx=50, pady=5)

menubar = tb.Menu(root)
root.config(menu=menubar)
menu_file = tb.Menu(menubar, tearoff=0) 
menu_help = tb.Menu(menubar, tearoff=0)

menubar.add_cascade(label='File', menu=menu_file)
menubar.add_cascade(label='Help', menu=menu_help)

menu_anagrafiche = tb.Menu(menu_file, tearoff=0)
menu_file.add_cascade(label='Anagrafiche', menu=menu_anagrafiche)
menu_file.add_separator()
menu_file.add_command(label='Import file')
menu_file.add_separator()
menu_file.add_command(label='Exit', command=root.destroy)

menu_help.add_command(label='Info')

root.mainloop()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 21:45:53