Tkinter嵌套窗口变量未定义:NameError问题求助
问题描述
使用Python 3.11.3搭配Spyder开发基于Tkinter的机器控制GUI(类似简易日志系统)。在主窗口(Ventana principal)中点击「No aceptable」按钮(boton_flujo_2)会弹出Toplevel窗口「Ventana 1」,需求是勾选该窗口内的「No necesario 2」时禁用窗口内的按钮。此逻辑在主窗口中可正常运行,但在嵌套窗口中触发错误:
NameError: name 'mensual_check_top1' is not defined
尝试设置全局变量也未解决问题。
原始代码
import tkinter as tk from tkinter import ttk # 根据条件禁用控件 def disable_widgets(): # 若Valve Status的"0 (cero)"被勾选,禁用下拉菜单 if cero_check.get() == 1: dropdown.config(state='disabled') else: dropdown.config(state='readonly') # 若"5lpm"被勾选,禁用流量输入框 if flow_check.instate(['selected']): flow_entry.config(state='disabled') else: flow_entry.config(state='normal') # 若CONTROL MENSUAL的"no necesario"被勾选,禁用对应按钮 if control_mensual_check.instate(['selected']): boton_flujo_1.config(state='disabled') boton_flujo_2.config(state='disabled') else: boton_flujo_1.config(state='normal') boton_flujo_2.config(state='normal') # 若Ventana 1的"No necesario 2"被勾选,禁用对应按钮 if mensual_check_top1.instate(['selected']): boton_flujo_3.config(state='disabled') boton_flujo_4.config(state='disabled') else: boton_flujo_3.config(state='normal') boton_flujo_4.config(state='normal') # 限制Status输入仅为数字 def validate_numeric_input(new_value): return new_value.isnumeric() # 创建Ventana 1窗口 def realizar_calibracion(): ventana1 = tk.Toplevel(root) ventana1.geometry("300x100") ventana1.title("Ventana 1") verif_flujo_mensual = ttk.Label(ventana1, text="Verificacion de flujo") verif_flujo_mensual.grid(row=0, column=1) mensual_check_top1 = ttk.Checkbutton(ventana1, text="No necesario 2", command=disable_widgets) mensual_check_top1.grid(row=2, column=0) boton_flujo_3 = ttk.Button(ventana1, text="Aceptable") boton_flujo_3.grid(row=2, column=1) boton_flujo_4 = ttk.Button(ventana1, text="No aceptable") boton_flujo_4.grid(row=2, column=2) # 主窗口 root = tk.Tk() root.title("Ventana Principal") root.geometry("800x600") # OPERADOR区域 operador_label = ttk.Label(root, text="Operador") operador_label.grid(row=0, column=0) operador_entry = ttk.Entry(root) operador_entry.grid(row=0, column=1) # STATUS区域(仅允许数字输入) status_label = ttk.Label(root, text="Status") status_label.grid(row=1, column=0) status_entry = ttk.Entry(root, validate="key") status_entry['validatecommand'] = (status_entry.register(validate_numeric_input), '%P') status_entry.grid(row=1, column=1) # VALVE STATUS区域 valve_status_label = ttk.Label(root, text="Valve Status") valve_status_label.grid(row=2, column=0) # 勾选"0 (cero)"时禁用下拉菜单 cero_check = tk.IntVar() cero_checkbox = ttk.Checkbutton(root, text="0 (cero)", variable=cero_check, command=disable_widgets) cero_checkbox.grid(row=2, column=1) # Valve Status非零选项下拉菜单 options_var = tk.StringVar() options = [" Otro valor ","01011 : Derivación", "01100 : Calentamiento/Aire limpio", "00000 : Medida", "00010 : Calibración medidor de flujo"] dropdown = ttk.OptionMenu(root, options_var, *options) dropdown.grid(row=2, column=2) # APARIENCIA DEL FILTRO区域 apariencia_filtro_label = ttk.Label(root, text="Apariencia Filtro") apariencia_filtro_label.grid(row=3, column=0) apariencia_filtro_options = ["APARIENCIA","Normal", "Achucharrado", "Marron"] apariencia_filtro_var = tk.StringVar(value="") apariencia_filtro_dropdown = ttk.OptionMenu(root, apariencia_filtro_var, *apariencia_filtro_options) apariencia_filtro_dropdown.grid(row=3, column=1) # FLUJO区域 flow_label = ttk.Label(root, text="Flujo") flow_label.grid(row=4, column=0) # 勾选"5lpm"时禁用输入框 flow_check = ttk.Checkbutton(root, text="5lpm", command=disable_widgets) flow_check.grid(row=4, column=1) # 流量输入框 flow_entry = ttk.Entry(root) flow_entry.grid(row=4, column=2) # CINTA REEMPLAZADA区域 replacement_tape_label = ttk.Label(root, text="Cinta reemplazada?") replacement_tape_label.grid(row=5, column=0) # 替换胶带勾选框 replacement_tape_check = ttk.Checkbutton(root, text="Si") replacement_tape_check.grid(row=5, column=1) # 分割线 division_label = ttk.Label(root, text="------------------------------") division_label.grid(row=7, column=1) # CHECKLIST GENERAL标题 general_label = ttk.Label(root, text="CHECKLIST GENERAL") general_label.grid(row=8, column=1) # CHECKLIST GENERAL区域 big_checkbox_var = tk.IntVar() big_checkbox = ttk.Checkbutton(root, width=0) big_checkbox.grid(row=9, column=1, rowspan=4) # 检查当前时间与仪器时间 hora_label = ttk.Label(root, text="Chequeo hora actual + instrumento") hora_label.grid(row=9, column=0) # 检查管道和软管 mangueras_label = ttk.Label(root, text="Inspeccion caños y mangueras") mangueras_label.grid(row=10, column=0) # 检查内部水阱 aguainterna_label = ttk.Label(root, text="Inspeccion trampa de agua interna") aguainterna_label.grid(row=11, column=0) # 检查外部水阱 aguaexterna_label = ttk.Label(root, text="Inspeccion trampa de agua externa") aguaexterna_label.grid(row=12, column=0) # 分割线 division_label = ttk.Label(root, text="------------------------------") division_label.grid(row=13, column=1) # CONTROL MENSUAL标题 general_label = ttk.Label(root, text="CONTROL MENSUAL") general_label.grid(row=14, column=1) # 流量验证标签 verif_flujo = ttk.Label(root, text="Verificacion de flujo") verif_flujo.grid(row=15, column=0) control_mensual_check = ttk.Checkbutton(root, text="No necesario", command=disable_widgets) control_mensual_check.grid(row=15, column=1) boton_flujo_1 = ttk.Button(root, text="Aceptable") boton_flujo_1.grid(row=15, column=2) boton_flujo_2 = ttk.Button(root, text="No aceptable",command=realizar_calibracion) boton_flujo_2.grid(row=15, column=3) root.mainloop()
解决方案
问题根源
mensual_check_top1、boton_flujo_3、boton_flujo_4是realizar_calibracion函数的局部变量,disable_widgets无法直接访问。- 主窗口启动时子窗口尚未创建,
disable_widgets中直接访问子窗口控件会触发变量未定义错误。
修复方案(全局变量+存在性判断)
修改realizar_calibracion函数,将子窗口控件声明为全局变量;同时在disable_widgets中先判断变量是否存在,再执行逻辑:
import tkinter as tk from tkinter import ttk # 全局变量声明,用于子窗口控件 mensual_check_top1 = None boton_flujo_3 = None boton_flujo_4 = None # 根据条件禁用控件 def disable_widgets(): # 若Valve Status的"0 (cero)"被勾选,禁用下拉菜单 if cero_check.get() == 1: dropdown.config(state='disabled') else: dropdown.config(state='readonly') # 若"5lpm"被勾选,禁用流量输入框 if flow_check.instate(['selected']): flow_entry.config(state='disabled') else: flow_entry.config(state='normal') # 若CONTROL MENSUAL的"no necesario"被勾选,禁用对应按钮 if control_mensual_check.instate(['selected']): boton_flujo_1.config(state='disabled') boton_flujo_2.config(state='disabled') else: boton_flujo_1.config(state='normal') boton_flujo_2.config(state='normal') # 先判断子窗口控件是否存在,再执行禁用逻辑 if mensual_check_top1 is not None and boton_flujo_3 is not None and boton_flujo_4 is not None: if mensual_check_top1.instate(['selected']): boton_flujo_3.config(state='disabled') boton_flujo_4.config(state='disabled') else: boton_flujo_3.config(state='normal') boton_flujo_4.config(state='normal') # 限制Status输入仅为数字 def validate_numeric_input(new_value): return new_value.isnumeric() # 创建Ventana 1窗口 def realizar_calibracion(): global mensual_check_top1, boton_flujo_3, boton_flujo_4 ventana1 = tk.Toplevel(root) ventana1.geometry("300x100") ventana1.title("Ventana 1") verif_flujo_mensual = ttk.Label(ventana1, text="Verificacion de flujo") verif_flujo_mensual.grid(row=0, column=1) mensual_check_top1 = ttk.Checkbutton(ventana1, text="No necesario 2", command=disable_widgets) mensual_check_top1.grid(row=2, column=0) boton_flujo_3 = ttk.Button(ventana1, text="Aceptable") boton_flujo_3.grid(row=2, column=1) boton_flujo_4 = ttk.Button(ventana1, text="No aceptable") boton_flujo_4.grid(row=2, column=2) # 主窗口 root = tk.Tk() root.title("Ventana Principal") root.geometry("800x600") # OPERADOR区域 operador_label = ttk.Label(root, text="Operador") operador_label.grid(row=0, column=0) operador_entry = ttk.Entry(root) operador_entry.grid(row=0, column=1) # STATUS区域(仅允许数字输入) status_label = ttk.Label(root, text="Status") status_label.grid(row=1, column=0) status_entry = ttk.Entry(root, validate="key") status_entry['validatecommand'] = (status_entry.register(validate_numeric_input), '%P') status_entry.grid(row=1, column=1) # VALVE STATUS区域 valve_status_label = ttk.Label(root, text="Valve Status") valve_status_label.grid(row=2, column=0) # 勾选"0 (cero)"时禁用下拉菜单 cero_check = tk.IntVar() cero_checkbox = ttk.Checkbutton(root, text="0 (cero)", variable=cero_check, command=disable_widgets) cero_checkbox.grid(row=2, column=1) # Valve Status非零选项下拉菜单 options_var = tk.StringVar() options = [" Otro valor ","01011 : Derivación", "01100 : Calentamiento/Aire limpio", "00000 : Medida", "00010 : Calibración medidor de flujo"] dropdown = ttk.OptionMenu(root, options_var, *options) dropdown.grid(row=2, column=2) # APARIENCIA DEL FILTRO区域 apariencia_filtro_label = ttk.Label(root, text="Apariencia Filtro") apariencia_filtro_label.grid(row=3, column=0) apariencia_filtro_options = ["APARIENCIA","Normal", "Achucharrado", "Marron"] apariencia_filtro_var = tk.StringVar(value="") apariencia_filtro_dropdown = ttk.OptionMenu(root, apariencia_filtro_var, *apariencia_filtro_options) apariencia_filtro_dropdown.grid(row=3, column=1) # FLUJO区域 flow_label = ttk.Label(root, text="Flujo") flow_label.grid(row=4, column=0) # 勾选"5lpm"时禁用输入框 flow_check = ttk.Checkbutton(root, text="5lpm", command=disable_widgets) flow_check.grid(row=4, column=1) # 流量输入框 flow_entry = ttk.Entry(root) flow_entry.grid(row=4, column=2) # CINTA REEMPLAZADA区域 replacement_tape_label = ttk.Label(root, text="Cinta reemplazada?") replacement_tape_label.grid(row=5, column=0) # 替换胶带勾选框 replacement_tape_check = ttk.Checkbutton(root, text="Si") replacement_tape_check.grid(row=5, column=1) # 分割线 division_label = ttk.Label(root, text="------------------------------") division_label.grid(row=7, column=1) # CHECKLIST GENERAL标题 general_label = ttk.Label(root, text="CHECKLIST GENERAL") general_label.grid(row=8, column=1) # CHECKLIST GENERAL区域 big_checkbox_var = tk.IntVar() big_checkbox = ttk.Checkbutton(root, width=0) big_checkbox.grid(row=9, column=1, rowspan=4) # 检查当前时间与仪器时间 hora_label = ttk.Label(root, text="Chequeo hora actual + instrumento") hora_label.grid(row=9, column=0) # 检查管道和软管 mangueras_label = ttk.Label(root, text="Inspeccion caños y mangueras") mangueras_label.grid(row=10, column=0) # 检查内部水阱 aguainterna_label = ttk.Label(root, text="Inspeccion trampa de agua interna") aguainterna_label.grid(row=11, column=0) # 检查外部水阱 aguaexterna_label = ttk.Label(root, text="Inspeccion trampa de agua externa") aguaexterna_label.grid(row=12, column=0) # 分割线 division_label = ttk.Label(root, text="------------------------------") division_label.grid(row=13, column=1) # CONTROL MENSUAL标题 general_label = ttk.Label(root, text="CONTROL MENSUAL") general_label.grid(row=14, column=1) # 流量验证标签 verif_flujo = ttk.Label(root, text="Verificacion de flujo") verif_flujo.grid(row=15, column=0) control_mensual_check = ttk.Checkbutton(root, text="No necesario", command=disable_widgets) control_mensual_check.grid(row=15, column=1) boton_flujo_1 = ttk.Button(root, text="Aceptable") boton_flujo_1.grid(row=15, column=2) boton_flujo_2 = ttk.Button(root, text="No aceptable",command=realizar_calibracion) boton_flujo_2.grid(row=15, column=3) root.mainloop()
优化建议(面向对象写法)
如果GUI复杂度提升,建议改用面向对象方式组织代码,避免全局变量,将控件和逻辑封装在类中,更易维护:
import tkinter as tk from tkinter import ttk class MachineControlGUI: def __init__(self, root): self.root = root self.root.title("Ventana Principal") self.root.geometry("800x600") self.mensual_check_top1 = None
相关产品推荐
相关产品推荐

