Python函数executelogin执行后程序无法继续运行的问题排查
问题:调用executelogin后程序后续代码无法执行
调用executelogin函数完成登录后,程序后面的代码完全不运行。以下是executelogin的代码:
def executelogin(): global initiate_game_window global checker counter = 1 while counter < 4: global login_tk, game, us1_entry, us2_entry, us1_pwd_entry, us2_pwd_entry login_tk = Tk(screenName="Login - RollADie") titlelabel = Label(text="Welcome to rollaDie", font=('Open Sans', '20')) titlelabel.grid(column=0, row=0, sticky=NSEW) sublabel = Label(text="Login Below: ", font=('Open Sans', '10')) sublabel.grid(column=0, row=1, sticky=NSEW) us1_label = Label(text="User 1:") us1_label.grid(row=2, column=0, sticky=NSEW) us1_entry = Entry(width=10, textvariable=us1_uname) us1_entry.grid(row=3, column=0, sticky=NSEW) us1_pwd_label = Label(text="Password:") us1_pwd_label.grid(row=4, column=0, sticky=NSEW) us1_pwd_entry = Entry(width=10, show="*", textvariable=us1_pwrd) us1_pwd_entry.grid(row=5, column=0, sticky=NSEW) us2_label = Label( text="User 2:") us2_label.grid(row=6, column=0, sticky=NSEW) us2_entry = Entry(width=10, textvariable=us2_uname) us2_entry.grid(row=7, column=0, sticky=NSEW) us2_pwd_label = Label(text="Password:") us2_pwd_label.grid(row=8, column=0, sticky=NSEW) us2_pwd_entry = Entry(width=10, show="*", textvariable=us2_pwrd) us2_pwd_entry.grid(row=9, column=0, sticky=NSEW) def get_credentials(): global us1_entry, us2_entry, us1_pwd_entry, us2_pwd_entry, top_login us1_uname = us1_entry.get() us1_pwrd = us1_pwd_entry.get() us2_uname = us2_entry.get() us2_pwrd = us2_pwd_entry.get() print(us1_uname, us1_pwrd, us2_uname, us2_pwrd) global credentials credentials = [us1_uname, us1_pwrd, us2_uname, us2_pwrd] top_login.destroy() global top_login top_login = tk.Toplevel() top_login.geometry('1x1+0+0') top_login.overrideredirect(True) submit_button = Button(text="Submit", command=get_credentials) submit_button.grid(row=10, column=0, sticky=NSEW) top_login.wait_window(top_login) us1_auth = False us2_auth = False if login(credentials[0], credentials[1]) == True: us1_auth = True else: pass if login(credentials[2], credentials[3]) == True: us2_auth = True else: pass if us1_auth == True: if us2_auth == True: print("Auth POS") messagebox.showinfo(message="AUTHORISED") login_tk.destroy() break else: print("User 2 AUTH NEG") messagebox.showinfo(message="User 2 Denied") counter += 1 if counter > 3: messagebox.showinfo(message="MAX ATTEMPTS") quit() continue else: print("AUTH USER 1 NEG") messagebox.showinfo(message="USER 1 NOT AUTHORISED") counter += 1 if counter > 3: messagebox.showinfo(message="MAX ATTEMPTS") quit() continue login_tk.mainloop()
executelogin下方的后续代码:
top = None top_roll2 = None faces = {'1':'⚀', '2':'⚁', '3':'⚂', '4':'⚃', '5':'⚄', '6':'⚅'} root = Tk(className='RollADice', screenName='RollADice') title = Label(text='RollADice by. Amen', font=('Open Sans', '20')).grid(row=0, column=0, sticky=NSEW) round_teller = Label(text='Currently: Round {0}'.format(roundnum)) round_teller.grid(row=1, column=0, sticky=NSEW) dicelabel = Label(root)
问题原因与解决方法
核心问题1:多个Tk实例+主循环阻塞
Tkinter程序绝对不能创建多个Tk()实例,每个程序只能有一个主Tk对象,否则会导致事件循环冲突,程序逻辑混乱。你的代码里,executelogin创建了login_tk = Tk(),后续又创建root = Tk(),这本身就是严重错误。
另外,executelogin最后调用了login_tk.mainloop(),这个主循环会阻塞程序,直到login_tk窗口被销毁,但即使销毁后,后续创建新的Tk实例依然会引发问题。
核心问题2:不必要的wait_window与窗口销毁逻辑
你用了一个隐藏的top_login Toplevel并调用wait_window,这个逻辑可以简化,而且认证成功后销毁login_tk,但之后还调用login_tk.mainloop(),此时窗口已经不存在,无意义且可能阻塞。
修复步骤:
改用单个主Tk实例:
先创建主窗口root,一开始隐藏,登录完成后再显示。登录窗口用Toplevel(root)创建,作为主窗口的子窗口。移除
executelogin中的login_tk.mainloop():
整个程序只需要在最后调用root.mainloop()即可,避免多次主循环阻塞。重构登录窗口逻辑:
把登录窗口改成Toplevel,去掉多余的隐藏Toplevel,直接用提交按钮触发认证逻辑,认证成功后销毁登录窗口并显示主窗口。
修复后的示例代码:
import tkinter as tk from tkinter import messagebox def login(username, password): # 这里替换成你的实际认证逻辑 return username == "user1" and password == "pass1" or username == "user2" and password == "pass2" def executelogin(root): counter = 1 while counter < 4: login_top = tk.Toplevel(root) login_top.title("Login - RollADie") tk.Label(login_top, text="Welcome to rollaDie", font=('Open Sans', '20')).grid(column=0, row=0, sticky=NSEW) tk.Label(login_top, text="Login Below: ", font=('Open Sans', '10')).grid(column=0, row=1, sticky=NSEW) # 用户1输入框 tk.Label(login_top, text="User 1:").grid(row=2, column=0, sticky=NSEW) us1_entry = tk.Entry(login_top, width=10) us1_entry.grid(row=3, column=0, sticky=NSEW) tk.Label(login_top, text="Password:").grid(row=4, column=0, sticky=NSEW) us1_pwd_entry = tk.Entry(login_top, width=10, show="*") us1_pwd_entry.grid(row=5, column=0, sticky=NSEW) # 用户2输入框 tk.Label(login_top, text="User 2:").grid(row=6, column=0, sticky=NSEW) us2_entry = tk.Entry(login_top, width=10) us2_entry.grid(row=7, column=0, sticky=NSEW) tk.Label(login_top, text="Password:").grid(row=8, column=0, sticky=NSEW) us2_pwd_entry = tk.Entry(login_top, width=10, show="*") us2_pwd_entry.grid(row=9, column=0, sticky=NSEW) credentials = [] def get_credentials(): nonlocal credentials credentials = [ us1_entry.get(), us1_pwd_entry.get(), us2_entry.get(), us2_pwd_entry.get() ] login_top.destroy() tk.Button(login_top, text="Submit", command=get_credentials).grid(row=10, column=0, sticky=NSEW) root.wait_window(login_top) # 等待登录窗口关闭 if not credentials: continue us1_auth = login(credentials[0], credentials[1]) us2_auth = login(credentials[2], credentials[3]) if us1_auth and us2_auth: print("Auth POS") messagebox.showinfo(message="AUTHORISED") return True elif not us1_auth: print("AUTH USER 1 NEG") messagebox.showinfo(message="USER 1 NOT AUTHORISED") else: print("User 2 AUTH NEG") messagebox.showinfo(message="User 2 Denied") counter += 1 if counter > 3: messagebox.showinfo(message="MAX ATTEMPTS") root.quit() return False return False # 主程序开始 if __name__ == "__main__": top = None top_roll2 = None faces = {'1':'⚀', '2':'⚁', '3':'⚂', '4':'⚃', '5':'⚄', '6':'⚅'} roundnum = 1 # 假设roundnum有定义 root = tk.Tk(className='RollADice', screenName='RollADice') root.withdraw() # 先隐藏主窗口 # 执行登录,成功后显示主窗口 if executelogin(root): root.deiconify() tk.Label(root, text='RollADice by. Amen', font=('Open Sans', '20')).grid(row=0, column=0, sticky=NSEW) round_teller = tk.Label(root, text='Currently: Round {0}'.format(roundnum)) round_teller.grid(row=1, column=0, sticky=NSEW) dicelabel = tk.Label(root) # 这里添加你的游戏逻辑 root.mainloop()
关键改动说明:
- 主程序只创建一个
root = Tk()实例,一开始隐藏,登录成功后显示。 - 登录窗口用
Toplevel(root)创建,避免多个Tk实例冲突。 - 用
root.wait_window(login_top)等待登录窗口关闭,代替原来的隐藏Toplevel逻辑,更清晰。 - 移除了所有全局变量的滥用,改用
nonlocal和参数传递,代码更健壮。 - 整个程序只有最后一个
root.mainloop(),避免阻塞后续代码执行。
内容的提问来源于stack exchange,提问作者Amen
相关产品推荐
相关产品推荐

