Tkinter弹窗关闭、Lambda使用疑问及界面修改技术咨询
问题描述
我正在开发一款测试用简易应用,程序从数据库加载用户名和密码(仅用于学习测试,不用于实际场景)。若用户名不在数据库中,应用需弹出新窗口询问是否将数据保存到数据库。目前应用可正常运行,但有几个需求和疑问:
- 实现点击“Yes”按钮后关闭该弹窗的功能
- 为何按钮的
command参数必须使用lambda?不使用lambda时,程序运行后会自动执行按钮指定的命令,这和Python解释器的工作机制有关吗?有没有常规方法可以避免这种情况? - 实现点击“Yes”后将该按钮改为“Close”、删除“No”按钮的功能
- 能否在
add_user_gumb函数中通过finally语句关闭窗口,无需声明新变量?
已尝试的代码如下:
弹窗类代码
class Window(): def __init__(self, username, password): self.root = tk.Toplevel() self.root.geometry("300x200") self.root.title("New user") new_user_label=tk.Label(self.root, text="Save user in database?") new_user_label.pack(padx=5, pady=5) btn_yes = tk.Button(self.root, text="Yes", command= lambda: add_user_gumb(session, username, password)) btn_yes.pack(padx=5, pady=5) btn_no = tk.Button(self.root, text="No", command= lambda: self.Close()) btn_no.pack(padx=5, pady=5) self.root.mainloop() def Close(self): self.root.destroy()
数据库操作函数代码
def add_user_gumb(session, username, password): #check existing_user = session.query(User).filter(User.username == username).one_or_none() if not existing_user: try: new_user = User(username=username, password=password, name=username) session.add(new_user) session.commit() print("User saved in DB!") except Exception as e: print(f' {e} while writing to DB!') else: print('User exists!') return
解决方案
1. 点击“Yes”后关闭弹窗
直接修改Yes按钮的command,把数据库操作和窗口关闭逻辑合并到lambda里即可:
# 替换原Window类中的btn_yes定义 btn_yes = tk.Button(self.root, text="Yes", command=lambda: [add_user_gumb(session, username, password), self.Close()])
点击Yes时,会先执行数据库保存,再关闭弹窗。
2. 关于lambda在command中的作用
- 为什么必须用lambda?
Tkinter的command参数需要的是无参数的可调用对象。如果直接写command=add_user_gumb(session, username, password),这是直接调用函数的语法,Python解释器在创建按钮时就会立刻执行这个函数,而不是等按钮点击才触发。lambda的作用就是封装一个无参数的匿名函数,只有点击按钮时才会执行里面的函数调用。 - 替代lambda的常规方法:
- 用
functools.partial绑定参数:from functools import partial # 替换btn_yes的command btn_yes = tk.Button(self.root, text="Yes", command=partial(add_user_gumb, session, username, password)) - 在类内部定义方法,把需要的参数存为实例属性:
class Window(): def __init__(self, username, password, session): self.session = session self.username = username self.password = password # ... 其他初始化代码 btn_yes = tk.Button(self.root, text="Yes", command=self.on_yes_click) # ... def on_yes_click(self): add_user_gumb(self.session, self.username, self.password) self.Close()
- 用
3. 点击“Yes”后修改按钮文本并删除“No”按钮
要修改按钮,得把按钮对象存为类的实例属性,这样后续才能操作它们:
class Window(): def __init__(self, username, password, session): self.session = session self.username = username self.password = password self.root = tk.Toplevel() self.root.geometry("300x200") self.root.title("New user") new_user_label=tk.Label(self.root, text="Save user in database?") new_user_label.pack(padx=5, pady=5) # 保存为实例属性 self.btn_yes = tk.Button(self.root, text="Yes", command=self.on_yes_click) self.btn_yes.pack(padx=5, pady=5) self.btn_no = tk.Button(self.root, text="No", command=self.Close) self.btn_no.pack(padx=5, pady=5) self.root.mainloop() def Close(self): self.root.destroy() def on_yes_click(self): add_user_gumb(self.session, self.username, self.password) # 修改Yes按钮为Close,点击直接关闭窗口 self.btn_yes.config(text="Close", command=self.Close) # 销毁No按钮 self.btn_no.destroy()
这样点击Yes后,Yes按钮变成Close,No按钮直接消失,点击Close就能关闭窗口。
4. 在add_user_gumb中用finally关闭窗口
可以实现,只要把窗口的关闭方法作为参数传给add_user_gumb就行,不用额外声明变量:
# 修改Window类中的on_yes_click方法 def on_yes_click(self): add_user_gumb(self.session, self.username, self.password, self.Close) # 修改add_user_gumb函数 def add_user_gumb(session, username, password, close_func): existing_user = session.query(User).filter(User.username == username).one_or_none() if not existing_user: try: new_user = User(username=username, password=password, name=username) session.add(new_user) session.commit() print("User saved in DB!") except Exception as e: print(f' {e} while writing to DB!') finally: close_func() # 不管操作成功失败,都关闭窗口 else: print('User exists!') close_func() return
这里把窗口的Close方法直接传给函数,在finally块里调用,确保无论数据库操作结果如何,窗口都会关闭。
内容的提问来源于stack exchange,提问作者geni0us
相关产品推荐
相关产品推荐

