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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 23:50:23