如何在Tkinter的Next类__init__中访问SampleApp的字典?解决KeyError
看起来你的问题主要来自两个方面:数据库查询结果的结构处理不当,以及页面初始化时机导致的字典键未定义。我来一步步帮你修复:
错误原因分析
数据库结果的结构问题:
你在StartPage中把daneUsera2 = self.cursor.fetchall()赋值给了self.controller.discUserInfo['data'],但fetchall()返回的是记录列表(每条记录是字典或元组),不是单个字典。所以当你在Next类里尝试self.controller.discUserInfo['data']['row1']时,本质是在给列表用字符串索引,自然会报错。页面初始化时机问题:
SampleApp在启动时就会创建所有页面(包括Next),这时候discUserInfo['data']还没有被赋值(只有登录成功后才会添加这个键),所以Next的__init__方法直接访问这个键会触发KeyError。
具体修复步骤
1. 正确处理数据库查询结果
在StartPage的_login_btn_clicked方法中,修改data的赋值逻辑,确保我们拿到的是单个记录字典(如果查询有结果的话):
# 原代码 self.controller.discUserInfo['data'] = daneUsera2 # 修改为 self.controller.discUserInfo['data'] = daneUsera2[0] if daneUsera2 else {}
这样如果查询到结果,我们取第一条记录;如果没有结果,就赋值一个空字典,避免后续访问出错。
2. 延迟设置Scale的值到页面显示时
不要在Next的__init__里直接设置Scale的值,而是在页面被切换显示的时候再设置。我们可以给Next添加一个on_show方法,然后修改SampleApp的show_frame方法来触发它:
修改SampleApp的show_frame方法
def show_frame(self, page_name): frame = self.frames[page_name] # 如果当前页面有on_show方法,就调用它 if hasattr(frame, 'on_show'): frame.on_show() frame.tkraise()
修改Next类的实现
class Next(tk.Frame): def __init__(self, parent, controller): tk.Frame.__init__(self, parent) self.controller = controller label = tk.Label(self, text="Next", font=controller.title_font) label.pack(side="top", fill="x", pady=10) buttonAudio = tk.Button(self, text="xx", command=self.ttt, width=20) buttonAudio.pack() # 先创建Scale组件,暂不设置默认值 self.w = tk.Scale(self, from_=0, to=8, orient='horizontal') self.w.pack() def on_show(self): # 当页面被显示时,再设置Scale的值 user_data = self.controller.discUserInfo.get('data', {}) # 使用get方法安全获取值,避免KeyError,默认值设为0 self.w.set(user_data.get('row1', 0)) def ttt(self): print(self.controller.discUserInfo)
3. 额外的安全措施
如果你的KeyError: 'testDatast'是笔误,上面的修复应该能解决问题;如果确实是这个键,你需要检查代码中哪里用到了这个键,确保在访问前已经将它添加到discUserInfo字典中。另外,建议在访问字典键时尽量使用get方法,比如dict.get(key, default_value),这样即使键不存在也不会抛出异常。
内容的提问来源于stack exchange,提问作者Jin Salim

