Python/tkinter对话框点击OK后内部result变量值丢失问题
问题根源
这是tkinter.simpledialog.Dialog的执行逻辑特性导致的,不存在什么初始化逻辑二次执行:
Dialog父类的构造方法__init__是阻塞运行的:调用后会直接完成对话框绘制、启动事件循环等待用户操作,直到用户点击按钮触发对话框销毁,整个交互流程跑完才会返回控制权。- 你写的子类
__init__里,把self.result = 'en'、self.selected_language初始化的代码放在了super().__init__()调用之后。实际执行顺序是:弹框→你选语言改了self.result→点OK对话框销毁→super()调用返回→你写在后面的self.result = 'en'直接把之前选好的值覆盖成了默认值,看起来就像值重置丢失了。 - 还有个冗余bug:你在
body方法里又给self.selected_language赋了个新的StringVar实例,等于__init__里创建的同名变量完全没被用到,属于无效代码。 - 网上可正常运行的同类自定义Dialog示例,属性初始化全都是放在父类构造调用之前的,顺序写反必然出现值被覆盖的问题。
修复方法
按规则调整即可:
- 所有实例属性的初始化代码,必须放在
super().__init__()调用之前,绝对不能放在父类构造方法后面 - 删掉
body里重复创建self.selected_language的冗余代码 - 按
Dialog的设计规范,重写apply()方法赋值最终返回结果,比在下拉框选中事件里实时改值更稳妥,能避免用户选了选项又直接关窗口的异常场景。
修复后可运行代码
import tkinter as tk from tkinter.simpledialog import Dialog from tkinter import ttk, LEFT, ACTIVE from tkinter.ttk import Button, Frame class LanguageDialog(Dialog): lang_dict = { 'italiano': 'it', 'español': 'es', 'english': 'en', 'galego': 'gl', } def __init__(self, parent, *args, **kwargs): # 所有实例属性初始化必须放在super()调用前 self.selected_language = tk.StringVar(value='english') self.result = 'en' # 默认值 super().__init__(parent, *args, **kwargs) def body(self, master): ops = tuple(self.lang_dict.keys()) cmb_lang = ttk.Combobox(self, values=ops, state='readonly', textvariable=self.selected_language) cmb_lang.pack(side=tk.TOP, padx=10, pady=10) # 初始化默认选中项 cmb_lang.current(2) return cmb_lang def apply(self): # 点击OK确认时最终赋值结果,不需要额外绑定下拉框事件 selected_text = self.selected_language.get() self.result = self.lang_dict[selected_text] def buttonbox(self): box = Frame(self) w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE) w.pack(side=LEFT, padx=5, pady=5) self.bind("<Return>", self.ok) box.pack() if __name__ == '__main__': root = tk.Tk() root.withdraw() # 隐藏多余的主窗口 d = LanguageDialog(root, title='选择语言') print(f'对话框关闭后,选中的语言代码:{d.result}') root.mainloop()
内容的提问来源于stack exchange,提问作者madtyn
相关产品推荐
相关产品推荐

