在类中创建Python tkinter下拉菜单后无法获取其状态变量值
问题根源
你现在拿不到下拉选中值,本质是封装逻辑存在两个设计缺陷:
- 仅返回了创建完成的
OptionMenu控件本体,没有对外暴露和这个控件绑定的StringVar状态变量,没有读取值的入口 - 把
StringVar直接存在封装类的self.state属性上,同一个封装类实例创建多个下拉菜单时,后续的创建逻辑会直接覆盖前面的self.state,导致所有已创建的下拉菜单都绑定最后生成的那个变量,出现值错乱的隐蔽bug - 方法参数里预留的
state参数完全没有参与逻辑,属于无效冗余代码
解决方案
根据你的使用习惯,可以二选一调整封装逻辑:
方案1:保留原有返回控件的调用习惯,把状态变量挂在控件实例上
不需要改动你现有调用方法的接收逻辑,只需要在创建下拉菜单时,把对应的状态变量作为自定义属性挂在OptionMenu实例上:
def make_drop_menu(self, parent, drop_opts, default_val=None): # 定义方法局部变量,每个下拉对应独立的状态变量,避免互相覆盖 current_state = tk.StringVar() # 默认值优先用传入值,未传入则取选项列表第一个 current_state.set(default_val if default_val is not None else drop_opts[0]) # 创建下拉菜单控件 drop_widget = OptionMenu(parent, current_state, *drop_opts) # 将绑定的状态变量作为自定义属性挂在控件上 drop_widget.linked_var = current_state # 仍然只返回控件本体,兼容原有调用逻辑 return drop_widget
调用和取值完全沿用你原来的写法:
# 原有的调用逻辑完全不需要改 self.widget = self.var.make_drop_menu(self.obj_mainwindow.btm_frame, self.col_opts) # 获取当前选中值,直接读控件上的linked_var属性即可 selected_value = self.widget.linked_var.get()
方案2:方法同时返回控件和状态变量
如果希望逻辑更清晰,也可以调整返回值为元组,同时返回控件和对应的状态变量:
def make_drop_menu(self, parent, drop_opts, default_val=None): current_state = tk.StringVar() current_state.set(default_val if default_val is not None else drop_opts[0]) drop_widget = OptionMenu(parent, current_state, *drop_opts) # 同时返回控件和状态变量 return drop_widget, current_state
调用时同时接收两个返回值即可:
# 同时接收控件和状态变量 self.col_menu, self.col_menu_var = self.var.make_drop_menu( self.obj_mainwindow.btm_frame, self.col_opts ) # 获取选中值直接调用状态变量的get方法 selected_value = self.col_menu_var.get()
注意:原逻辑里把self.state作为类全局属性存储状态变量的写法有严重隐患,同一个封装类实例创建多个下拉时,所有下拉的绑定变量会被最后一次创建的实例覆盖,必须把每个下拉对应的状态变量做成方法内的局部变量,才能保证每个下拉的状态独立
内容的提问来源于stack exchange,提问作者Eric Connaisseur
相关产品推荐
相关产品推荐

