Tkinter BMI计算器:重复计算时旧结果标签无法销毁的问题求助
问题
我开发的BMI计算器功能正常,但用户输入新值重新计算时,之前显示的结果标签会残留。我尝试写代码让calc函数重新运行时销毁第一个标签,但始终无法实现——不管把destroyLabel()函数放哪,都会报'lblResult'标签未定义的错,就算把它设成全局变量也没用。求解决方案。
附带代码
import tkinter as tk window = tk.Tk() # 创建GUI窗口 window.title("BMI") # 设置窗口标题 window.geometry("300x230") # 设置窗口尺寸 photo = tk.PhotoImage(file="Calculator.png") # 设置窗口图标 window.iconphoto(False, photo) global lblResult def destroyLabel(): lblResult.destroy() def calc(): try: height = float(entry1.get()) # 获取身高输入并转为浮点数 weight = float(entry2.get()) # 获取体重输入并转为浮点数 bmi = weight / (height ** 2) # BMI计算公式 if bmi < 16: lblResult = tk.Label(window, text="Severely underweight", fg="blue") elif 16 <= bmi < 18.5: lblResult = tk.Label(window, text="Underweight", fg="green") elif 18.5 <= bmi < 25: lblResult = tk.Label(window, text="Healthy", fg="goldenrod") elif 25 <= bmi < 30: lblResult = tk.Label(window, text="Overweight", fg="orange") elif bmi >= 30: lblResult = tk.Label(window, text="Severely overweight", fg="red") except: lblResult = tk.Label(window, text="Error!", fg="red") lblResult.grid(row=7, column=1) # 将结果标签添加到GUI lblTitle = tk.Label(window, # 设置界面标题 text="BMI Calculator", font="Arial 14 bold", ) lblTitle.grid(row=0, column=0) lblSpace = tk.Label(window) # 添加空白行分隔标签 lblSpace.grid(row=1, column=0) lblHeight = tk.Label(window, # 设置身高标签 text="Height in metres", font="Arial 10 bold", ) lblHeight.grid(row=2, column=0) lblWeight = tk.Label(window, # 设置体重标签 text="Weight in KG", font="Arial 10 bold", ) lblWeight.grid(row=3, column=0) entry1 = tk.Entry(window) # 创建身高输入框 entry1.grid(row=2, column=1, columnspan=2, padx=(1, 1), pady=(1, 1)) # 放置输入框 entry2 = tk.Entry(window) # 创建体重输入框 entry2.grid(row=3, column=1, columnspan=2, padx=(1, 1), pady=(1, 1)) # 放置输入框 lblSpace = tk.Label(window) # 添加空白行分隔 lblSpace.grid(row=4, column=0) btnCalc = tk.Button(window, # 创建计算BMI按钮 text="Calculate BMI", font="Arial 12 bold", fg="red", command=lambda: calc() ) btnCalc.grid(row=5, column=0, padx=(1, 1), pady=(1, 1)) # 放置按钮 btnQuit = tk.Button(window, # 创建退出按钮 text="Quit", font="Arial 12 bold", fg="red", width="12", command=lambda: window.destroy() ) btnQuit.grid(row=5, column=1, padx=(1, 1), pady=(1, 1)) # 放置按钮 lblSpace = tk.Label(window) # 添加空白行分隔 lblSpace.grid(row=6, column=0) lblBMI = tk.Label(window, # 添加BMI标签 text="BMI: ", font="Arial 12 bold") lblBMI.grid(row=7, column=0) window.mainloop() # 启动窗口主循环
解决方案
核心问题分析
你声明了全局变量lblResult,但在calc函数里给它赋值时,没有再次用global声明,导致函数里的lblResult是局部变量,全局的那个根本没被赋值——这就是销毁时提示未定义的原因。而且每次计算都新建Label控件,既冗余又容易出现重叠问题,更优的做法是复用同一个Label,只更新它的内容和样式。
推荐方案:复用结果标签(更高效简洁)
初始化时就创建好结果标签,之后在calc函数里直接修改它的文本和颜色,不用反复创建销毁控件:
修改后的完整代码:
import tkinter as tk window = tk.Tk() window.title("BMI") window.geometry("300x230") photo = tk.PhotoImage(file="Calculator.png") window.iconphoto(False, photo) # 提前创建结果标签,初始为空 lblResult = tk.Label(window, text="", font="Arial 12") lblResult.grid(row=7, column=1) def calc(): try: height = float(entry1.get()) weight = float(entry2.get()) bmi = weight / (height ** 2) # 直接更新已存在的lblResult的文本和颜色 if bmi < 16: lblResult.config(text="Severely underweight", fg="blue") elif 16 <= bmi < 18.5: lblResult.config(text="Underweight", fg="green") elif 18.5 <= bmi < 25: lblResult.config(text="Healthy", fg="goldenrod") elif 25 <= bmi < 30: lblResult.config(text="Overweight", fg="orange") elif bmi >= 30: lblResult.config(text="Severely overweight", fg="red") except: lblResult.config(text="Error!", fg="red") # 以下部分和原代码一致,无需修改 lblTitle = tk.Label(window, text="BMI Calculator", font="Arial 14 bold", ) lblTitle.grid(row=0, column=0) lblSpace = tk.Label(window) lblSpace.grid(row=1, column=0) lblHeight = tk.Label(window, text="Height in metres", font="Arial 10 bold", ) lblHeight.grid(row=2, column=0) lblWeight = tk.Label(window, text="Weight in KG", font="Arial 10 bold", ) lblWeight.grid(row=3, column=0) entry1 = tk.Entry(window) entry1.grid(row=2, column=1, columnspan=2, padx=(1, 1), pady=(1, 1)) entry2 = tk.Entry(window) entry2.grid(row=3, column=1, columnspan=2, padx=(1, 1), pady=(1, 1)) lblSpace = tk.Label(window) lblSpace.grid(row=4, column=0) btnCalc = tk.Button(window, text="Calculate BMI", font="Arial 12 bold", fg="red", command=calc # 这里可以直接写calc,不用lambda ) btnCalc.grid(row=5, column=0, padx=(1, 1), pady=(1, 1)) btnQuit = tk.Button(window, text="Quit", font="Arial 12 bold", fg="red", width="12", command=window.destroy ) btnQuit.grid(row=5, column=1, padx=(1, 1), pady=(1, 1)) lblSpace = tk.Label(window) lblSpace.grid(row=6, column=0) lblBMI = tk.Label(window, text="BMI: ", font="Arial 12 bold") lblBMI.grid(row=7, column=0) window.mainloop()
补充说明
- 用
config()方法修改控件属性是Tkinter的标准做法,比反复创建销毁控件更高效。 - 按钮的
command参数可以直接传函数名(比如command=calc),不需要用lambda包裹,除非需要传参数。
备选方案:修复全局变量问题(不推荐,冗余)
如果一定要坚持销毁重建标签,需要在calc函数里正确声明全局变量,并先判断标签是否存在:
import tkinter as tk window = tk.Tk() window.title("BMI") window.geometry("300x230") photo = tk.PhotoImage(file="Calculator.png") window.iconphoto(False, photo) lblResult = None # 初始化全局变量为None def calc(): global lblResult # 必须在函数里声明使用全局变量 # 如果标签已存在,先销毁 if lblResult is not None: lblResult.destroy() try: height = float(entry1.get()) weight = float(entry2.get()) bmi = weight / (height ** 2) if bmi < 16: lblResult = tk.Label(window, text="Severely underweight", fg="blue") elif 16 <= bmi < 18.5: lblResult = tk.Label(window, text="Underweight", fg="green") elif 18.5 <= bmi < 25: lblResult = tk.Label(window, text="Healthy", fg="goldenrod") elif 25 <= bmi < 30: lblResult = tk.Label(window, text="Overweight", fg="orange") elif bmi >= 30: lblResult = tk.Label(window, text="Severely overweight", fg="red") except: lblResult = tk.Label(window, text="Error!", fg="red") lblResult.grid(row=7, column=1) # 其余代码和原代码一致...
内容的提问来源于stack exchange,提问作者Silver
相关产品推荐
相关产品推荐

