Tkinter中on_return方法触发KeyError: 'id'问题求助
解决UpdateStudent框架跳转时的KeyError问题
每次点击前一窗口的更新按钮,后续的UpdateStudent框架无法正常显示,终端弹出如下错误:
Exception in Tkinter callback Traceback (most recent call last): File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.1008.0_x64__qbz5n2kfra8p0\Lib\tkinter\__init__.py", line 1948, in __call__ return self.func(*args) ^^^^^^^^^^^^^^^^ File "c:\Users\Charles Mendoza\Desktop\Student Management System\pages.py", line 868, in update_student self.go_to_update_form() File "c:\Users\Charles Mendoza\Desktop\Student Management System\pages.py", line 880, in go_to_update_form self.parent.change_window("UpdateStudent") File "c:\Users\Charles Mendoza\Desktop\Student Management System\main.py", line 36, in change_window self.frames[name].on_return(**kwargs) File "c:\Users\Charles Mendoza\Desktop\Student Management System\pages.py", line 1420, in on_return self.student_id = kwargs['id'] ~~~~~~^^^^^^ KeyError: 'id'
以下是UpdateStudent类的完整代码:
class UpdateStudent(Frame): def __init__(self, master): Frame.__init__(self, master) self.parent = master self.background = Image.open('pictures/school.jpg') self.image_res = self.background.resize((1000, 800)) self.picture = ImageTk.PhotoImage(self.image_res) self.background_panel = Label(self, image = self.picture) self.background_panel.pack(fill = BOTH, expand = 'yes') self.login_box = Frame(self, bg='#DAD8D8', width = "970", height = "770") self.login_box.place (x = 10, y = 10) self.id_label = Label(self, text = "ID:",bg='#DAD8D8') self.id_label.place(x = 105, y = 20) self.id_label2 = Label(self, text = "XX" , bg = "#DAD8D8") self.id_label2.place(x = 150, y = 20) self.student_name_label = Label(self, text ="Student Name:", bg = "#DAD8D8") self.student_name_label.place(x = 40, y = 40 ) self.student_name_field = Entry(self) self.student_name_field.place(x = 140, y = 40, width = 180) self.course_label = Label(self, text = "Course:", bg = "#DAD8D8") self.course_label.place(x= 80, y = 60 ) self.course_field = Entry(self) self.course_field.place(x =140, y = 60, width = 180) self.birthdate_label = Label(self, text = "Birthdate:", bg = "#DAD8D8") self.birthdate_label.place(x = 70, y = 80) self.birthdate_field = Entry(self) self.birthdate_field.place(x = 140, y = 80, width = 180 ) self.gender_label = Label(self, text = "Gender:", bg = "#DAD8D8") self.gender_label.place(x = 80, y = 100 ) self.gender_field = Entry(self) self.gender_field.place(x =140, y = 100, width = 180 ) self.contact_number_label = Label(self, text = "Contact Number:", bg = "#DAD8D8") self.contact_number_label.place(x = 30, y = 120 ) self.contact_number_field = Entry(self) self.contact_number_field.place(x =140, y = 120, width = 180 ) self.email_label = Label(self, text = "Email:", bg = "#DAD8D8") self.email_label.place(x =90, y = 140) self.email_field = Entry(self) self.email_field.place(x = 140, y = 140, width = 180) self.instructor_label = Label(self, text = "Instructor:", bg = "#DAD8D8") self.instructor_label.place(x = 70, y = 160) self.instructor_field = Entry(self) self.instructor_field.place(x = 140, y = 160, width = 180) self.balance_label = Label(self, text = "Balance:", bg = "#DAD8D8") self.balance_label.place(x = 80, y = 180) self.balance_field = Entry(self) self.balance_field.place(x = 140, y = 180, width = 180) self.username_label = Label(self, text = "Username:", bg = "#DAD8D8") self.username_label.place(x = 70, y = 200) self.username_field = Entry(self) self.username_field.place(x = 140, y = 200, width = 180) self.password_label = Label(self, text = "Password:", bg = "#DAD8D8") self.password_label.place(x =70, y = 220 ) self.password_field = Entry(self) self.password_field.place(x = 140, y = 220, width = 180) self.update_button = Button(self, text="Update Information", command = self.update_student) self.update_button.place(x = 200, y = 250) columns = ('id', 'balance') self.table = ttk.Treeview(self, columns = columns, show = 'headings', selectmode = 'browse') self.table.heading('id', text = "Student ID") self.table.heading('balance', text = "Balance") self.table.column('id', width = 200) self.table.column('balance', width = 120) self.table.place(x = 400, y = 40) self.table.config(height = 20) self.update_table() def update_table(self, event = None): self.student_list = self.get_student_list() self.table.delete(*self.table.get_children()) for student in self.student_list: row = ( student.student_name, student.course, student.birthdate, student.gender, student.contact_number, student.email, student.instructor, student.balance, student.username, student.password, student.grade ) self.table.insert('', END, values = row) def get_student_list(self): db_conn = database_handler.DBHandler() self.Student_list = db_conn.read_student() db_conn.close() return self.Student_list def validate_data(self): return True def update_student(self): if not self.validate_data(): return try: self.student_name = self.student_name_field.get() self.course = self.course_field.get() self.birthdate = self.birthdate_field.get() self.gender = self.gender_field.get() self.contact_number = int(self.contact_number_field.get()) self.email = self.email_field.get() self.instructor = self.instructor_field.get() self.balance = float(self.balance_field.get()) self.username = self.username_field.get() self.password = self.password_field.get() db_conn = database_handler.DBHandler() db_conn.update_student(self.student_list) db_conn.close() self.go_to_view_students() except ValueError: messagebox.showerror('Update Student', "Contact Number and Balance must be a number") def update_table(self, event = None): self.get_student_list() self.table.delete(*self.table.get_children()) for student in self.Student_list: row = (student.student_name, student.balance) self.table.insert('', END, values = row) def go_to_view_students(self): self.parent.change_window("RegistrarViewStudents") def on_return(self, **kwargs,): self.student_id = kwargs['id'] self.id_label.config(text=self.student_id) db_conn = database_handler.DBHandler() self.student = db_conn.read_one_student(self.student_id) db_conn.close() self.clear_data() self.init_data() def init_data(self): self.student_name_field.insert(0, self.student.student_name) self.course_field.insert(0, self.student.course) self.birthdate_field.insert(0, self.student.birthdate) self.gender_field.insert(0, self.student.gender) self.contact_number_field.insert(0, int(self.student.contact_number)) self.email_field.insert(0, self.student.email) self.instructor_field.insert(0, self.student.instructor) self.balance_field.insert(0, float(self.student.balance)) self.username_field.insert(0, self.student.username) self.password_field.insert(0, self.student.password) self.update_table() def clear_data(self): self.student_name_field.delete(0, END) self.course_field.delete(0, END) self.birthdate_field.delete(0, END) self.gender_field.delete(0, END) self.contact_number_field.delete(0, END) self.email_field.delete(0, END) self.instructor_field.delete(0, END) self.balance_field.delete(0, END) self.username_field.delete(0, END) self.password_field.delete(0, END)
问题分析
- KeyError根源:前一窗口调用
change_window("UpdateStudent")时,未传入包含学生ID的参数,导致on_return方法无法从kwargs中获取id。 - 代码冗余问题:类中定义了两个同名的
update_table方法,后定义的会覆盖前一个,导致表格渲染逻辑混乱。 - 更新逻辑错误:
update_student方法传入整个学生列表而非单个学生对象,不符合单条数据更新的业务逻辑。
修复方案
1. 补全跳转时的参数传递
修改前一窗口的go_to_update_form方法,传入选中的学生ID:
def go_to_update_form(self): # 获取Treeview中选中的学生ID(根据实际列索引调整) selected_item = self.table.selection()[0] student_id = self.table.item(selected_item)['values'][0] self.parent.change_window("UpdateStudent", id=student_id)
2. 增强on_return的容错性
添加参数缺失判断,避免程序崩溃:
def on_return(self, **kwargs): self.student_id = kwargs.get('id') if not self.student_id: messagebox.showerror("错误", "未选择要更新的学生") self.go_to_view_students() return self.id_label.config(text=self.student_id) db_conn = database_handler.DBHandler() self.student = db_conn.read_one_student(self.student_id) db_conn.close() self.clear_data() self.init_data()
3. 合并重复的update_table方法
删除重复方法,保留匹配表格列定义的版本:
def update_table(self, event=None): self.get_student_list() self.table.delete(*self.table.get_children()) for student in self.Student_list: # 匹配columns定义的('id', 'balance')列 row = (student.id, student.balance) self.table.insert('', END, values=row)
4. 修正单条学生数据更新逻辑
修改update_student方法,传入单个学生的更新数据:
def update_student(self): if not self.validate_data(): return try: updated_student = { 'id': self.student_id, 'student_name': self.student_name_field.get(), 'course': self.course_field.get(), 'birthdate': self.birthdate_field.get(), 'gender': self.gender_field.get(), 'contact_number': int(self.contact_number_field.get()), 'email': self.email_field.get(), 'instructor': self.instructor_field.get(), 'balance': float(self.balance_field.get()), 'username': self.username_field.get(), 'password': self.password_field.get() } db_conn = database_handler.DBHandler() db_conn.update_student(updated_student) db_conn.close() messagebox.showinfo("成功", "学生信息更新完成") self.go_to_view_students() except ValueError: messagebox.showerror('更新学生', "联系电话和余额必须为数字")
内容的提问来源于stack exchange,提问作者Charles Mendoza
相关产品推荐
相关产品推荐

