Tkinter GUI仅重启Python Kernel可正常运行,非新Kernel下值固定默认
Tkinter GUI重复运行无法获取新输入值问题
问题描述
- 开发了一个基于Tkinter的参数配置GUI工具,首次运行时功能正常,能正确获取输入框内容
- 在Spyder中不重启Python Kernel再次运行时,输入框始终返回默认值(
X和5.0),无法捕获新输入的内容 - 新Kernel下运行结果:
({'Option 1': '4', 'Option 2': '4', 'Option 3': '7'}, 5.5) - 非新Kernel下运行结果:
({'Option 1': 'X', 'Option 2': 'X', 'Option 3': 'X'}, 5.0)
原代码
# -*- coding: utf-8 -*- """ Created on Mon Aug 26 08:55:59 2024 @author: khourym """ import tkinter as tk from tkinter import ttk # Function to create a top-level dropdown GUI and return dictionary on submit def create_dropdowns(options, root): # This dictionary will hold the labels as keys and dropdown values as values result = {} def validate_float_input(char, text): """ Validate the input for the float entry. """ print(char) if ( all(char in "0123456789.-" for char in text) and # all characters are valid "-" not in text[1:] and # "-" is the first character or not present text.count(".") <= 1): # only 0 or 1 periods return True else: return False def on_submit(): # Update the result dictionary with the current dropdown selections for option, var in variables.items(): print(var.get()) result[option] = var.get() # Get the current value of the dropdown # Get the value of the float entry sv_value = float_entry_var.get() top.destroy() # Close the top-level window return result, sv_value # Create a top-level window top = tk.Toplevel(root, background="cyan") top.title("Top-Level Dropdown GUI") # Create a frame to hold all dropdowns infoFrame = tk.Frame(top,background="cyan") infoFrame.pack() cTile = tk.Label(infoFrame, text="Please configure the Control Logic states in\n voltage with the VIH values and enter the nominal \nvoltage for the supply voltage(VCC) all in volts",background="cyan") cTile.pack(expand=False, fill='both') frame = tk.Frame(top, background="cyan") frame.pack() # Create a dictionary to hold variables associated with dropdown values variables = {} # Iterate over the array of strings and create a label and dropdown for each for option in options: dropdown_label = tk.Label(frame, text="Enter the value for the control logic " + option, background="cyan") dropdown_label.pack(anchor="w") var = tk.StringVar(value="X") # default value is "X" float_entry = tk.Entry(frame, textvariable=var) float_entry.pack(anchor="w") variables[option] = var # Create a label and entry box for the float value float_label = tk.Label(frame, text="Enter The supply voltage VIH value", background="cyan") float_label.pack(anchor="w") float_entry_var = tk.StringVar(value="5.0") # default value is "0.0" # Register the validation function vcmd = (root.register(validate_float_input), "%S", "%P") float_entry = tk.Entry(frame, textvariable=float_entry_var, validate="key", validatecommand=vcmd) float_entry.pack(anchor="w") # Create a submit button submit_button = tk.Button(top, text="Submit", command=on_submit, background="skyblue") submit_button.pack(pady=10) # Start the Tkinter main loop root.wait_window(top) # Return the result dictionary with the label-value pairs and the float value return result, float(float_entry_var.get()) if __name__ == "__main__": # Example usage options_array = ["Option 1", "Option 2", "Option 3"] root = tk.Tk() root.withdraw() # Hide the root window, only show the top-level window selected_values = create_dropdowns(options_array,root) print(selected_values) # This will print the dictionary after you close the top-level GUI
问题根源
在Spyder的持久化Kernel环境中,重复运行代码会创建多个tk.Tk()根窗口实例。Tkinter不允许同时存在多个根窗口,导致后续运行的GUI组件绑定失效,无法正确触发按钮事件或读取输入值。此外,第一次运行后的根窗口仅被withdraw()隐藏而非销毁,残留实例会干扰后续运行流程。
修复方案
方案1:复用已有根窗口
修改__main__代码块,检查是否存在已创建的根窗口实例,复用它而非重复创建:
if __name__ == "__main__": options_array = ["Option 1", "Option 2", "Option 3"] # 检查是否已有根窗口实例,避免重复创建 try: root.state() # 尝试获取已有root的状态,不存在则抛出NameError except NameError: root = tk.Tk() root.withdraw() # 隐藏根窗口 selected_values = create_dropdowns(options_array, root) print(selected_values)
方案2:运行后销毁根窗口
在__main__块末尾添加根窗口销毁代码,确保每次运行结束后清理所有Tk资源:
if __name__ == "__main__": options_array = ["Option 1", "Option 2", "Option 3"] root = tk.Tk() root.withdraw() # 隐藏根窗口,仅显示顶层配置窗口 selected_values = create_dropdowns(options_array, root) print(selected_values) # 运行结束后销毁根窗口,清理资源 root.destroy()
额外优化(可选)
on_submit函数中的return语句无实际作用(Tkinter按钮命令的返回值会被自动丢弃),当前依赖修改外部result字典的逻辑可行,但如果需要更清晰的状态管理,可以改用类封装GUI逻辑,不过对于小型工具,现有逻辑无需大幅改动。
验证效果
修改后无需重启Kernel,重复运行代码即可正常获取新输入的参数值,不会再返回默认值。
内容的提问来源于stack exchange,提问作者Khoury
相关产品推荐
相关产品推荐

