使用模块要求:
tkinter、numpy、openpyxl、matplotlib、pymysql、re、time;其中matplotlib用于绘制统计图
开发工具:pycharm专业版、python3.7、mysql8.0
运行效果:
主页面:
教师端主要功能:
教师端登录后的效果——成绩分析页面:
成绩分析页面——课程成绩分析(统计图):
各班级创建分析页面——统计图:
班级综合成绩评定页面——扇形统计图:
修改密码页面:
课程管理页面——根据学院、考试方式进行添加或删除课程:
Teacherpage.py页面代码如下:
from tkinter import *
from tkinter import messagebox, filedialog
from tkinter.ttk import *
import openpyxl as openpyxl
import AddCoursePage
import AddScorePage
import ClassGradeAnalysis
import ComprehensivePerformanceEvaluation
import CourseScoreAnalysis
import Dao
import DeleteCoursePage
import DeleteScorePage
import Login
import UpdateCoursePage
import AddStudentPage
import DeleteStudentPage
import UpdateScorePage
import UpdateStudentPage
import numpy as np
import matplotlib.pyplot as plt
class WinGUI(Tk):
def __init__(self):
super().__init__()
self.__win()
self.tk_label_title = self.__tk_label_title()
self.tk_label_current_user = self.__tk_label_current_user()
self.tk_tabs_content = Frame_content(self)
self.tk_button_logout_user = self.__tk_button_logout_user()
def __win(self):
self.title("教师端")
# 设置窗口大小、居中
width = 1000
height = 600
screenwidth = self.winfo_screenwidth()
screenheight = self.winfo_screenheight()
geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
self.geometry(geometry)
self.resizable(width=False, height=False)
self.iconbitmap('logo.ico')
def __tk_label_title(self):
label = Label(self, text="学生成绩管理系统", anchor="center")
label.place(x=0, y=0, width=800, height=100)
return label
def __tk_label_current_user(self):
label = Label(self, text="当前用户:admin", anchor="center")
label.place(x=800, y=70, width=150, height=30)
return label
def __tk_button_logout_user(self):
btn = Button(self, text="退出")
btn.place(x=950, y=70, width=50, height=30)
return btn
class Frame_content(Notebook):
def __init__(self, parent):
super().__init__(parent)
self.__frame()
def __frame(self):
self.tk_tabs_content_0 = Frame_content_0(self)
self.add(self.tk_tabs_content_0, text="个人资料")
self.tk_tabs_content_1 = Frame_content_1(self)
self.add(self.tk_tabs_content_1, text="学生查询")
self.tk_tabs_content_2 = Frame_content_2(self)
self.add(self.tk_tabs_content_2, text="成绩查询")
self.tk_tabs_content_3 = Frame_content_3(self)
self.add(self.tk_tabs_content_3, text="成绩分析")
self.tk_tabs_content_4 = Frame_content_4(self)
self.add(self.tk_tabs_content_4, text="修改密码")
self.tk_tabs_content_5 = Frame_content_5(self)
self.add(self.tk_tabs_content_5, text="课程管理")
self.place(x=0, y=100, width=1000, height=500)
class Frame_content_0(Frame):
def __init__(self, parent):
super().__init__(parent)
self.__frame()
self.tk_label_tea_number = self.__tk_label_tea_number()
self.tk_input_tea_number = self.__tk_input_tea_number()
self.tk_label_tea_name = self.__tk_label_tea_name()
self.tk_input_tea_name = self.__tk_input_tea_name()
self.tk_label_tea_gender = self.__tk_label_tea_gender()
self.tk_select_tea_gender = self.__tk_select_tea_gender()
self.tk_label_tea_identity = self.__tk_label_tea_identity()
self.tk_input_tea_identity = self.__tk_input_tea_identity()
self.tk_label_tea_email = self.__tk_label_tea_email()
self.tk_input_tea_email = self.__tk_input_tea_email()
self.tk_button_tea_update = self.__tk_button_tea_update()
self.tk_button_tea_reset = self.__tk_button_tea_reset()
def __frame(self):
self.place(x=0, y=100, width=1000, height=500)
def __tk_label_tea_number(self):
label = Label(self, text="工号", anchor="e")
label.place(x=360, y=40, width=100, height=30)
return label
def __tk_input_tea_number(self):
self.tea_number = StringVar(self)
ipt = Entry(self, text=self.tea_number)
ipt.place(x=490, y=40, width=150, height=30)
ipt.config(stat='disable')
return ipt
def __tk_label_tea_name(self):
label = Label(self, text="姓名", anchor="e")
label.place(x=360, y=110, width=100, height=30)
return label
def __tk_input_tea_name(self):
self.tea_name = StringVar(self)
ipt = Entry(self, text=self.tea_name)
ipt.place(x=490, y=110, width=150, height=30)
return ipt
def __tk_label_tea_gender(self):
label = Label(self, text="性别", anchor="e")
label.place(x=360, y=180, width=100, height=30)
return label
def __tk_select_tea_gender(self):
cb = Combobox(self, state='readonly')
cb['values'] = ("男", "女")
cb.place(x=490, y=180, width=150, height=30)
return cb
def __tk_label_tea_identity(self):
label = Label(self, text="身份证号", anchor="e")
label.place(x=360, y=250, width=100, height=30)
return label
def __tk_input_tea_identity(self):
self.tea_identify = StringVar(self)
ipt = Entry(self, text=self.tea_identify)
ipt.place(x=490, y=250, width=150, height=30)
return ipt
def __tk_label_tea_email(self):
label = Label(self, text="电子邮箱", anchor="e")
label.place(x=360, y=320, width=100, height=30)
return label
def __tk_input_tea_email(self):
self.tea_email = StringVar(self)
ipt = Entry(self, text=self.tea_email)
ipt.place(x=490, y=320, width=150, height=30)
return ipt
def __tk_button_tea_update(self):
btn = Button(self, text="修改")
btn.place(x=400, y=390, width=80, height=30)
return btn
def __tk_button_tea_reset(self):
btn = Button(self, text="重置")
btn.place(x=520, y=390, width=80, height=30)
return btn
class Frame_content_1(Frame):
def __init__(self, parent):
super().__init__(parent)
self.__frame()
self.tk_table_student_query = self.__tk_table_student_query()
self.tk_input_stu_name = self.__tk_input_stu_name()
self.tk_select_box_stu_gender = self.__tk_select_box_stu_gender()
self.tk_button_stu_search = self.__tk_button_stu_search()
self.tk_button_addStudent = self.__tk_button_addStudent()
self.tk_button_delete_student = self.__tk_button_delete_student()
self.tk_button_stu_refresh = self.__tk_button_stu_refresh()
self.tk_button_studentinfo_export = self.__tk_button_studentinfo_export()
def __frame(self):
self.place(x=0, y=100, width=1000, height=500)
def __tk_table_student_query(self):
# 表头字段 表头宽度
self.tk_table_student_manage_columns = {"ID": 50, "学号": 100, "姓名": 150, '性别': 100, '身份证号': 300, '班级': 100, '邮箱': 200}
# 初始化表格 表格是基于Treeview,tkinter本身没有表格。show="headings" 为隐藏首列。
tk_table = Treeview(self, show="headings", columns=list(self.tk_table_student_manage_columns))
for text, width in self.tk_table_student_manage_columns.items(): # 批量设置列属性
tk_table.heading(text, text=text, anchor='center')
tk_table.column(text, anchor='center', width=width, stretch=False) # stretch 不自动拉伸
# 插入数据示例
#
# # 导入初始数据
self.tk_student_table_dataset = Dao.getAllStudents()
if self.tk_student_table_dataset.get("code") == 0:
if self.tk_student_table_dataset.get("data"):
print(self.tk_student_table_dataset.get("data"))
for values in self.tk_student_table_dataset.get("data"):
tk_table.insert('', END, values=list(values.values()))
else:
print("未查询到数据!")
else:
print("数据查询异常!")
tk_table.place(x=0, y=60, width=1000, height=415)
return tk_table
def __tk_input_stu_name(self):
ipt = Entry(self)
ipt.place(x=360, y=10, width=150, height=30)
return ipt
def __tk_select_box_stu_gender(self):
cb = Combobox(self, state="readonly")
cb['values'] = ("请选择性别", "男", "女")
cb.place(x=540, y=10, width=150, height=30)
cb.current(0)
return cb
def __tk_button_stu_search(self):
btn = Button(self, text="搜索")
btn.place(x=720, y=10, width=70, height=30)
return btn
def __tk_button_stu_refresh(self):
btn = Button(self, text="刷新")
btn.place(x=820, y=10, width=70, height=30)
return btn
def __tk_button_addStudent(self):
btn = Button(self, text="添加学生")
btn.place(x=50, y=10, width=100, height=30)
return btn
def __tk_button_delete_student(self):
btn = Button(self, text="删除学生")
btn.place(x=180, y=10, width=100, height=30)
return btn
def __tk_button_studentinfo_export(self):
btn = Button(self, text="导出")
btn.place(x=920, y=10, width=50, height=30)
return btn
class Frame_content_2(Frame):
def __init__(self, parent):
super().__init__(parent)
self.__frame()
self.tk_table_stu_score = self.__tk_table_stu_score()
self.tk_button_add_score = self.__tk_button_add_score()
self.tk_button_delete_score = self.__tk_button_delete_score()
self.tk_select_box_score_course_name = self.__tk_select_box_score_course_name()
self.tk_select_box_score_nature = self.__tk_select_box_score_nature()
self.tk_select_box_score_department = self.__tk_select_box_score_department()
self.tk_button_stu_score_search = self.__tk_button_stu_score_search()
self.tk_button_stu_score_export = self.__tk_button_stu_score_export()
def __frame(self):
self.place(x=0, y=100, width=1000, height=500)
def __tk_table_stu_score(self):
# 表头字段 表头宽度
self.tk_table_stu_score_columns = {"#": 50, "学号": 70, "姓名": 80, "课程名称": 200, "课程性质": 100, "开课学院": 270, "考试方式": 80, "学分": 50, "成绩": 100}
# 初始化表格 表格是基于Treeview,tkinter本身没有表格。show="headings" 为隐藏首列。
tk_table = Treeview(self, show="headings", columns=list(self.tk_table_stu_score_columns))
for text, width in self.tk_table_stu_score_columns.items(): # 批量设置列属性
tk_table.heading(text, text=text, anchor='center')
tk_table.column(text, anchor='center', width=width, stretch=False) # stretch 不自动拉伸
# 插入数据示例
self.tk_score_table_dataset = Dao.searchStudentScore()
# 导入初始数据
if self.tk_score_table_dataset.get("code") == 0 and self.tk_score_table_dataset.get("data"):
for data in self.tk_score_table_dataset.get("data"):
tk_table.insert('', END, values=list(data.values()))
tk_table.place(x=0, y=60, width=1000, height=415)
return tk_table
def __tk_button_add_score(self):
btn = Button(self, text="添加成绩")
btn.place(x=50, y=10, width=100, height=30)
return btn
def __tk_button_delete_score(self):
btn = Button(self, text="删除成绩")
btn.place(x=170, y=10, width=100, height=30)
return btn
def __tk_select_box_score_course_name(self):
cb = Combobox(self, state="readonly")
values = ["请选择课程名称"]
for i in Dao.getAllCourses().get("data"):
values.append(i.get("cname"))
cb['values'] = values
cb.current(0)
cb.place(x=290, y=10, width=150, height=30)
return cb
def __tk_select_box_score_nature(self):
cb = Combobox(self, state="readonly")
values = ["请选择课程性质"]
for i in Dao.getDataDictByType("nature").get("data"):
values.append(i.get("v"))
cb['values'] = values
cb.current(0)
cb.place(x=460, y=10, width=150, height=30)
return cb
def __tk_select_box_score_department(self):
cb = Combobox(self, state="readonly")
values = ["请选择开课学院"]
for i in Dao.getAllDepartments().get("data"):
values.append(i.get("v"))
cb['values'] = values
cb.current(0)
cb.place(x=630, y=10, width=150, height=30)
return cb
def __tk_button_stu_score_search(self):
btn = Button(self, text="搜索")
btn.place(x=800, y=10, width=70, height=30)
return btn
def __tk_button_stu_score_export(self):
btn = Button(self, text="导出")
btn.place(x=890, y=10, width=70, height=30)
return btn
class Frame_content_3(Frame):
def __init__(self, parent):
super().__init__(parent)
self.__frame()
self.tk_button_pieChart = self.__tk_button_pieChart()
self.tk_button_columnChart = self.__tk_button_columnChart()
self.tk_button_paratacticColumnChart = self.__tk_button_paratacticColumnChart()
def __frame(self):
self.place(x=0, y=100, width=1000, height=500)
def __tk_button_columnChart(self):
btn = Button(self, text="课程成绩分析")
btn.place(x=80, y=50, width=150, height=70)
return btn
def __tk_button_paratacticColumnChart(self):
btn = Button(self, text="班级成绩分析")
btn.place(x=420, y=50, width=150, height=70)
return btn
def __tk_button_pieChart(self):
btn = Button(self, text="综合成绩评定")
btn.place(x=760, y=50, width=150, height=70)
return btn
class Frame_content_4(Frame):
def __init__(self, parent):
super().__init__(parent)
self.__frame()
self.tk_label_original_pwd = self.__tk_label_original_pwd()
self.tk_input_original_pwd = self.__tk_input_original_pwd()
self.tk_label_new_pwd = self.__tk_label_new_pwd()
self.tk_input_new_pwd = self.__tk_input_new_pwd()
self.tk_label_confirm_pwd = self.__tk_label_confirm_pwd()
self.tk_input_confirm_pwd = self.__tk_input_confirm_pwd()
self.tk_button_update_tea_pwd = self.__tk_button_update_tea_pwd()
def __frame(self):
self.place(x=0, y=100, width=1000, height=500)
def __tk_label_original_pwd(self):
label = Label(self, text="原密码", anchor="e")
label.place(x=360, y=40, width=100, height=30)
return label
def __tk_input_original_pwd(self):
ipt = Entry(self, show='*')
ipt.place(x=490, y=40, width=150, height=30)
return ipt
def __tk_label_new_pwd(self):
label = Label(self, text="新密码", anchor="e")
label.place(x=360, y=110, width=100, height=30)
return label
def __tk_input_new_pwd(self):
ipt = Entry(self, show='*')
ipt.place(x=490, y=110, width=150, height=30)
return ipt
def __tk_label_confirm_pwd(self):
label = Label(self, text="确认密码", anchor="e")
label.place(x=360, y=180, width=100, height=30)
return label
def __tk_input_confirm_pwd(self):
ipt = Entry(self, show='*')
ipt.place(x=490, y=180, width=150, height=30)
return ipt
def __tk_button_update_tea_pwd(self):
btn = Button(self, text="修改")
btn.place(x=450, y=260, width=100, height=30)
return btn
class Frame_content_5(Frame):
def __init__(self, parent):
super().__init__(parent)
self.__frame()
self.tk_table_course_manage = self.__tk_table_course_manage()
self.tk_button_add_course = self.__tk_button_add_course()
self.tk_button_delete_course = self.__tk_button_delete_course()
self.tk_select_box_course_department = self.__tk_select_box_course_department()
self.tk_select_box_course_exam_method = self.__tk_select_box_course_exam_method()
self.tk_button_course_search = self.__tk_button_course_search()
self.tk_button_course_export = self.__tk_button_course_export()
def __frame(self):
self.place(x=0, y=100, width=1000, height=500)
def __tk_table_course_manage(self):
# 表头字段 表头宽度
self.tk_table_course_manage_columns = {"课程号": 100, "课程名称": 200, "学分": 100, "课程性质": 200, "开课学院": 300, "考试方式": 100}
# 初始化表格 表格是基于Treeview,tkinter本身没有表格。show="headings" 为隐藏首列。
tk_table = Treeview(self, show="headings", columns=list(self.tk_table_course_manage_columns))
for text, width in self.tk_table_course_manage_columns.items(): # 批量设置列属性
tk_table.heading(text, text=text, anchor='center')
tk_table.column(text, anchor='center', width=width, stretch=False) # stretch 不自动拉伸
# 插入数据示例
self.tk_course_table_dataset = Dao.getAllCourses()
# 导入初始数据
if self.tk_course_table_dataset.get("code") == 0 and self.tk_course_table_dataset.get("data"):
for data in self.tk_course_table_dataset.get("data"):
tk_table.insert('', END, values=list(data.values()))
tk_table.place(x=0, y=60, width=1000, height=415)
return tk_table
def __tk_button_add_course(self):
btn = Button(self, text="添加课程")
btn.place(x=50, y=10, width=100, height=30)
return btn
def __tk_button_delete_course(self):
btn = Button(self, text="删除课程")
btn.place(x=180, y=10, width=100, height=30)
return btn
def __tk_select_box_course_department(self):
cb = Combobox(self, state="readonly")
values = ["请选择开课学院"]
for i in Dao.getAllDepartments().get("data"):
values.append(i.get("v"))
cb['values'] = values
cb.current(0)
cb.place(x=310, y=10, width=150, height=30)
return cb
def __tk_select_box_course_exam_method(self):
cb = Combobox(self, state="readonly")
values = ["请选择考试方式"]
for i in Dao.getDataDictByType("exammethod").get("data"):
values.append(i.get("v"))
cb['values'] = values
cb.current(0)
cb.place(x=490, y=10, width=150, height=30)
return cb
def __tk_button_course_search(self):
btn = Button(self, text="搜索")
btn.place(x=670, y=10, width=100, height=30)
return btn
def __tk_button_course_export(self):
btn = Button(self, text="导出")
btn.place(x=800, y=10, width=100, height=30)
return btn
class Win(WinGUI):
def __init__(self, current_user):
super().__init__()
self.__event_bind()
self.current_user = current_user
self.uid = current_user.get("uid")
self.tk_label_current_user['text'] = "当前用户:" + current_user.get("uname")
self.tk_tabs_content.tk_tabs_content_0.tea_number.set(current_user.get("uid"))
self.tk_tabs_content.tk_tabs_content_0.tea_name.set(current_user.get("uname"))
self.tk_tabs_content.tk_tabs_content_0.tk_select_tea_gender.current(0 if current_user.get("ugender") == '男' else 1)
self.tk_tabs_content.tk_tabs_content_0.tea_identify.set(current_user.get("uidentify"))
self.tk_tabs_content.tk_tabs_content_0.tea_email.set(current_user.get("uemail"))
def logout(self):
try:
self.updateStudent.destroy()
self.addInfo.destroy()
self.delete.destroy()
except Exception as e:
print(e)
messagebox.showwarning('提示', '欢迎下次使用!')
self.destroy()
login = Login.Win()
login.mainloop()
def updateStudentInfo(self, evt):
current_focus = self.tk_tabs_content.tk_tabs_content_1.tk_table_student_query.focus()
current_studentinfo = self.tk_tabs_content.tk_tabs_content_1.tk_table_student_query.set(current_focus)
current_uid = current_studentinfo.get('学号')
self.updateStudent = UpdateStudentPage.Win(current_uid)
self.updateStudent.mainloop()
print("<>事件未处理", evt)
def updateTeacherInfo(self, evt):
__tea_name = self.tk_tabs_content.tk_tabs_content_0.tk_input_tea_name.get()
__tea_gender = self.tk_tabs_content.tk_tabs_content_0.tk_select_tea_gender.get()
__tea_identify = self.tk_tabs_content.tk_tabs_content_0.tk_input_tea_identity.get()
__tea_email = self.tk_tabs_content.tk_tabs_content_0.tk_input_tea_email.get()
if not __tea_name or not __tea_gender or not __tea_identify or not __tea_email:
messagebox.showinfo("提示", "必填项不能为空!")
return
if not re.match(r'^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$',
__tea_identify):
messagebox.showinfo("提示", "身份证格式不合法!")
return
if not re.match(r'^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$', __tea_email):
messagebox.showinfo("提示", "电子邮箱格式不合法!")
return
res = Dao.updateUser(self.uid, __tea_name, __tea_gender, __tea_identify, 0, __tea_email)
messagebox.showinfo("提示", res.get("msg"))
self.tk_label_current_user['text'] = "当前用户:" + __tea_name
print("更新教师信息", evt)
def resetTeacherInfo(self, evt):
self.tk_tabs_content.tk_tabs_content_0.tea_name.set(self.current_user.get("uname"))
self.tk_tabs_content.tk_tabs_content_0.tk_select_tea_gender.current(0 if self.current_user.get("ugender") == '男' else 1)
self.tk_tabs_content.tk_tabs_content_0.tea_identify.set(self.current_user.get("uidentify"))
self.tk_tabs_content.tk_tabs_content_0.tea_email.set(self.current_user.get("uemail"))
print("重置教师信息", evt)
def searchStudentInfo(self, evt):
for _ in map(self.tk_tabs_content.tk_tabs_content_1.tk_table_student_query.delete,
self.tk_tabs_content.tk_tabs_content_1.tk_table_student_query.get_children("")):
pass
value = self.tk_tabs_content.tk_tabs_content_1.tk_input_stu_name.get()
num = self.tk_tabs_content.tk_tabs_content_1.tk_select_box_stu_gender.get()
print(num, value)
if num == '请选择性别':
result = Dao.searchStudents(value, '')
else:
result = Dao.searchStudents(value, num)
if result.get("code") == 0:
if result.get("data"):
# print(result.get("data"))
for values in result.get("data"):
self.tk_tabs_content.tk_tabs_content_1.tk_table_student_query.insert('', END, values=list(values.values()))
else:
print("未查询到数据!")
else:
print("数据查询异常!")
print("搜索学生信息", evt)
def updateStudentScore(self, evt):
current_item = self.tk_tabs_content.tk_tabs_content_2.tk_table_stu_score.set(self.tk_tabs_content.tk_tabs_content_2.tk_table_stu_score.focus())
data = {
"uid": current_item.get("学号"),
"cname": current_item.get("课程名称"),
"score": current_item.get("成绩")
}
updateScorePage = UpdateScorePage.Win(data)
updateScorePage.mainloop()
print("修改学生课程成绩", evt)
def searchStuScore(self, evt):
__score_manage = self.tk_tabs_content.tk_tabs_content_2
__course_name = __score_manage.tk_select_box_score_course_name.get()
__course_nature = __score_manage.tk_select_box_score_nature.get()
__course_department = __score_manage.tk_select_box_score_department.get()
if __score_manage.tk_select_box_score_course_name.current() == 0:
__course_name = ''
if __score_manage.tk_select_box_score_nature.current() == 0:
__course_nature = ''
if __score_manage.tk_select_box_score_department.current() == 0:
__course_department = ''
for _ in map(__score_manage.tk_table_stu_score.delete, __score_manage.tk_table_stu_score.get_children("")):
pass
__score_manage.tk_score_table_dataset = Dao.searchStudentScore(__course_name, __course_nature, __course_department)
# 导入初始数据
if __score_manage.tk_score_table_dataset.get("code") == 0 and __score_manage.tk_score_table_dataset.get("data"):
for data in __score_manage.tk_score_table_dataset.get("data"):
__score_manage.tk_table_stu_score.insert('', END, values=list(data.values()))
__score_manage.tk_select_box_score_course_name.current(0)
__score_manage.tk_select_box_score_nature.current(0)
__score_manage.tk_select_box_score_department.current(0)
print("搜索学生成绩!")
def exportStuScore(self, evt):
path = filedialog.askdirectory()
try:
book = openpyxl.Workbook()
sheet = book.active
fff = list(self.tk_tabs_content.tk_tabs_content_2.tk_table_stu_score_columns.keys()) # 获取表头信息
sheet.append(fff)
dataset = [list(data_item.values()) for data_item in
self.tk_tabs_content.tk_tabs_content_2.tk_score_table_dataset.get("data")]
print(dataset)
for i in dataset:
sheet.append(i)
book.save(f"{path}/student_score.xlsx")
messagebox.showinfo("提示", "导出成功!")
except Exception as e:
messagebox.showinfo("提示", "导出失败!")
print(e)
print("导出学生成绩!", evt)
def addStudentInfo(self, evt):
self.addInfo = AddStudentPage.Win()
self.addInfo.mainloop()
print("事件未处理", evt)
def deleteStudentInfo(self, evt):
self.delete = DeleteStudentPage.Win()
self.delete.mainloop()
print("事件未处理", evt)
def addStudentScore(self, evt):
addScorePage = AddScorePage.Win()
addScorePage.mainloop()
def deleteStudentScore(self, evt):
deleteScorePage = DeleteScorePage.Win()
deleteScorePage.mainloop()
print("删除学生成绩", evt)
def updateTeacherPassword(self, evt):
__original_pwd = self.tk_tabs_content.tk_tabs_content_4.tk_input_original_pwd.get()
__new_pwd = self.tk_tabs_content.tk_tabs_content_4.tk_input_new_pwd.get()
__confirm_pwd = self.tk_tabs_content.tk_tabs_content_4.tk_input_confirm_pwd.get()
if __original_pwd == '' or __new_pwd == '' or __confirm_pwd == '':
messagebox.showwarning("提示", "必填项未填写!")
return
if not re.match(r"^[0-9a-zA-Z~!@#$%^&*._?]{6,18}$", __original_pwd) \
or not re.match(r"^[0-9a-zA-Z~!@#$%^&*._?]{6,18}$", __new_pwd) \
or not re.match(r"^[0-9a-zA-Z~!@#$%^&*._?]{6,18}$", __confirm_pwd):
messagebox.showwarning("提示", "密码格式应为6-18位数字、字母、特殊字符的组合!")
return
if __new_pwd != __confirm_pwd:
messagebox.showwarning("提示", "两次密码输入不一致")
return
res = Dao.updatePassword(self.uid, __original_pwd, __new_pwd)
messagebox.showinfo("提示", res.get("msg"))
if res.get("code") == 0:
self.destroy()
login = Login.Win()
login.mainloop()
print("修改教师密码", evt)
def addCourseInfo(self, evt):
addCoursePage = AddCoursePage.Win()
addCoursePage.mainloop()
print("添加成绩!")
def deleteCourseInfo(self, evt):
deleteCoursePage = DeleteCoursePage.Win()
deleteCoursePage.mainloop()
print("删除课程!")
def searchCourseInfo(self, evt):
__course_manage = self.tk_tabs_content.tk_tabs_content_5
__department = __course_manage.tk_select_box_course_department.get()
__exammethod = __course_manage.tk_select_box_course_exam_method.get()
if __course_manage.tk_select_box_course_department.current() == 0:
__department = ''
if __course_manage.tk_select_box_course_exam_method.current() == 0:
__exammethod = ''
for _ in map(__course_manage.tk_table_course_manage.delete, __course_manage.tk_table_course_manage.get_children("")):
pass
self.tk_tabs_content.tk_tabs_content_5.tk_course_table_dataset = Dao.searchCourses(__department, __exammethod)
# 导入初始数据
if self.tk_tabs_content.tk_tabs_content_5.tk_course_table_dataset.get("code") == 0 and self.tk_tabs_content.tk_tabs_content_5.tk_course_table_dataset.get("data"):
for data in self.tk_tabs_content.tk_tabs_content_5.tk_course_table_dataset.get("data"):
__course_manage.tk_table_course_manage.insert('', END, values=list(data.values()))
__course_manage.tk_select_box_course_department.current(0)
__course_manage.tk_select_box_course_exam_method.current(0)
print("查询课程!")
def updateCourseInfo(self, evt):
__focus = self.tk_tabs_content.tk_tabs_content_5.tk_table_course_manage.focus()
current_item = self.tk_tabs_content.tk_tabs_content_5.tk_table_course_manage.set(__focus)
__cid = current_item.get("课程号")
self.updateCoursePage = UpdateCoursePage.Win(__cid)
self.updateCoursePage.mainloop()
print("更新课程信息!")
def exportCourseInfo(self, evt):
path = filedialog.askdirectory()
try:
book = openpyxl.Workbook()
sheet = book.active
fff = list(self.tk_tabs_content.tk_tabs_content_5.tk_table_course_manage_columns.keys()) # 获取表头信息
sheet.append(fff)
dataset = [list(data_item.values()) for data_item in self.tk_tabs_content.tk_tabs_content_5.tk_course_table_dataset.get("data")]
print(dataset)
for i in dataset:
sheet.append(i)
book.save(path + "/course_info.xlsx")
messagebox.showinfo("提示", "导出成功!")
except Exception as e:
messagebox.showinfo("提示", "导出失败!")
print(e)
def logout_user(self, evt):
messagebox.showwarning('提示', '欢迎下次使用!')
self.destroy()
login = Login.Win()
login.mainloop()
def studentinfo_refresh(self, evt):
# 删除原结点,加入新结点
for _ in map(self.tk_tabs_content.tk_tabs_content_1.tk_table_student_query.delete,
self.tk_tabs_content.tk_tabs_content_1.tk_table_student_query.get_children("")):
pass
result = Dao.getAllStudents()
if result.get("code") == 0:
if result.get("data"):
# print(result.get("data"))
for values in result.get("data"):
self.tk_tabs_content.tk_tabs_content_1.tk_table_student_query.insert('', END,
values=list(values.values()))
else:
print("未查询到数据!")
else:
print("数据查询异常!")
def studentinfo_export(self, evt):
path = filedialog.askdirectory()
try:
book = openpyxl.Workbook()
sheet = book.active
fff = list(self.tk_tabs_content.tk_tabs_content_1.tk_table_student_manage_columns.keys()) # 获取表头信息
sheet.append(fff)
dataset = [list(data_item.values()) for data_item in
self.tk_tabs_content.tk_tabs_content_1.tk_student_table_dataset.get("data")]
print(dataset)
for i in dataset:
sheet.append(i)
book.save(path + "/student_info.xlsx")
messagebox.showinfo("提示", "导出成功!")
except Exception as e:
messagebox.showinfo("提示", "导出失败!")
print(e)
def columnChart(self, evt):
courseScoreAnalysis = CourseScoreAnalysis.Win()
courseScoreAnalysis.mainloop()
def paratacticColumnChart(self, evt):
classGradeAnalysis = ClassGradeAnalysis.Win()
classGradeAnalysis.mainloop()
def pieChart(self, evt):
comprehensivePerformanceEvaluation = ComprehensivePerformanceEvaluation.Win()
comprehensivePerformanceEvaluation.mainloop()
def __event_bind(self):
self.protocol('WM_DELETE_WINDOW', self.logout)
self.tk_tabs_content.tk_tabs_content_1.tk_table_student_query.bind('<>', self.updateStudentInfo)
self.tk_tabs_content.tk_tabs_content_0.tk_button_tea_update.bind('', self.updateTeacherInfo)
self.tk_tabs_content.tk_tabs_content_0.tk_button_tea_reset.bind('', self.resetTeacherInfo)
self.tk_tabs_content.tk_tabs_content_1.tk_button_stu_search.bind('', self.searchStudentInfo)
self.tk_tabs_content.tk_tabs_content_1.tk_button_addStudent.bind('', self.addStudentInfo)
self.tk_tabs_content.tk_tabs_content_1.tk_button_delete_student.bind('', self.deleteStudentInfo)
self.tk_tabs_content.tk_tabs_content_1.tk_button_stu_refresh.bind('', self.studentinfo_refresh)
self.tk_tabs_content.tk_tabs_content_1.tk_button_studentinfo_export.bind('', self.studentinfo_export)
self.tk_tabs_content.tk_tabs_content_2.tk_button_add_score.bind('', self.addStudentScore)
self.tk_tabs_content.tk_tabs_content_2.tk_button_delete_score.bind('', self.deleteStudentScore)
self.tk_tabs_content.tk_tabs_content_2.tk_table_stu_score.bind('<>', self.updateStudentScore)
self.tk_tabs_content.tk_tabs_content_2.tk_button_stu_score_search.bind('', self.searchStuScore)
self.tk_tabs_content.tk_tabs_content_2.tk_button_stu_score_export.bind('', self.exportStuScore)
self.tk_tabs_content.tk_tabs_content_3.tk_button_columnChart.bind('', self.columnChart)
self.tk_tabs_content.tk_tabs_content_3.tk_button_paratacticColumnChart.bind('', self.paratacticColumnChart)
self.tk_tabs_content.tk_tabs_content_3.tk_button_pieChart.bind('', self.pieChart)
self.tk_tabs_content.tk_tabs_content_4.tk_button_update_tea_pwd.bind('', self.updateTeacherPassword)
self.tk_tabs_content.tk_tabs_content_5.tk_button_add_course.bind('', self.addCourseInfo)
self.tk_tabs_content.tk_tabs_content_5.tk_button_delete_course.bind('', self.deleteCourseInfo)
self.tk_tabs_content.tk_tabs_content_5.tk_button_course_search.bind('', self.searchCourseInfo)
self.tk_tabs_content.tk_tabs_content_5.tk_button_course_export.bind('', self.exportCourseInfo)
self.tk_tabs_content.tk_tabs_content_5.tk_table_course_manage.bind('<>', self.updateCourseInfo)
self.tk_button_logout_user.bind('', self.logout_user)
学生端登录页面效果:
学生端——成绩分析:
学生端——修改密码:
学生端代码如下:
student.py:
from tkinter import *
from tkinter import messagebox, filedialog
from tkinter.ttk import *
import numpy as np
import openpyxl
from matplotlib import pyplot as plt
import Dao
import Login
global current_uid
class WinGUI(Tk):
def __init__(self):
super().__init__()
self.__win()
self.tk_label_title = self.__tk_label_title()
self.tk_label_current_user = self.__tk_label_current_user()
self.tk_tabs_content = Frame_content(self)
self.tk_button_logout = self.__tk_button_logout()
def __win(self):
self.title("成绩查询")
# 设置窗口大小、居中
width = 1000
height = 600
screenwidth = self.winfo_screenwidth()
screenheight = self.winfo_screenheight()
geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
self.geometry(geometry)
self.resizable(width=False, height=False)
self.iconbitmap('logo.ico')
def __tk_label_title(self):
label = Label(self, text="学生成绩管理系统", anchor="center")
label.place(x=0, y=0, width=800, height=100)
return label
def __tk_label_current_user(self):
label = Label(self, text="当前用户:admin", anchor="center")
label.place(x=800, y=70, width=150, height=30)
return label
def __tk_button_logout(self):
btn = Button(self, text="退出")
btn.place(x=950, y=70, width=50, height=30)
return btn
class Frame_content(Notebook):
def __init__(self, parent):
super().__init__(parent)
self.__frame()
def __frame(self):
self.tk_tabs_content_0 = Frame_content_0(self)
self.add(self.tk_tabs_content_0, text="个人资料")
self.tk_tabs_content_1 = Frame_content_1(self)
self.add(self.tk_tabs_content_1, text="成绩查询")
self.tk_tabs_content_3 = Frame_content_3(self)
self.add(self.tk_tabs_content_3, text="修改密码")
self.place(x=0, y=100, width=1000, height=500)
class Frame_content_0(Frame):
def __init__(self, parent):
super().__init__(parent)
self.__frame()
self.tk_label_stu_number = self.__tk_label_stu_number()
self.tk_input_stu_number = self.__tk_input_stu_number()
self.tk_label_stu_name = self.__tk_label_stu_name()
self.tk_input_stu_name = self.__tk_input_stu_name()
self.tk_label_stu_gender = self.__tk_label_stu_gender()
self.tk_tk_select_stu_gender = self.__tk_select_stu_gender()
self.tk_label_stu_identity = self.__tk_label_stu_identity()
self.tk_input_stu_identity = self.__tk_input_stu_identity()
self.tk_label_stu_email = self.__tk_label_stu_email()
self.tk_input_stu_email = self.__tk_input_stu_email()
self.tk_button_stu_update = self.__tk_button_stu_update()
self.tk_button_stu_reset = self.__tk_button_stu_reset()
def __frame(self):
self.place(x=0, y=100, width=1000, height=500)
def __tk_label_stu_number(self):
label = Label(self, text="学号", anchor="e")
label.place(x=360, y=40, width=100, height=30)
return label
def __tk_input_stu_number(self):
self.student_number = StringVar(self)
ipt = Entry(self, text=self.student_number)
ipt.place(x=490, y=40, width=150, height=30)
ipt.config(stat='disable')
return ipt
def __tk_label_stu_name(self):
label = Label(self, text="姓名", anchor="e")
label.place(x=360, y=110, width=100, height=30)
return label
def __tk_input_stu_name(self):
self.student_name = StringVar(self)
ipt = Entry(self, text=self.student_name)
ipt.place(x=490, y=110, width=150, height=30)
return ipt
def __tk_label_stu_gender(self):
label = Label(self, text="性别", anchor="e")
label.place(x=360, y=180, width=100, height=30)
return label
def __tk_select_stu_gender(self):
cb = Combobox(self, state='readonly')
cb['values'] = ("男", "女")
cb.place(x=490, y=180, width=150, height=30)
return cb
def __tk_label_stu_identity(self):
label = Label(self, text="身份证号", anchor="e")
label.place(x=360, y=250, width=100, height=30)
return label
def __tk_input_stu_identity(self):
self.student_identify = StringVar(self)
ipt = Entry(self, text=self.student_identify)
ipt.place(x=490, y=250, width=150, height=30)
return ipt
def __tk_label_stu_email(self):
label = Label(self, text="电子邮箱", anchor="e")
label.place(x=360, y=320, width=100, height=30)
return label
def __tk_input_stu_email(self):
self.student_email = StringVar(self)
ipt = Entry(self, text=self.student_email)
ipt.place(x=490, y=320, width=150, height=30)
return ipt
def __tk_button_stu_update(self):
btn = Button(self, text="修改")
btn.place(x=400, y=390, width=80, height=30)
return btn
def __tk_button_stu_reset(self):
btn = Button(self, text="重置")
btn.place(x=520, y=390, width=80, height=30)
return btn
class Frame_content_1(Frame):
def __init__(self, parent):
super().__init__(parent)
self.__frame()
self.tk_button_analysis = self.__tk_button_analysis()
self.tk_table_stu_score = self.__tk_table_stu_score()
self.tk_select_box_course_nature = self.__tk_select_box_course_nature()
self.tk_select_box_course_department = self.__tk_select_box_course_department()
self.tk_select_box_exam_method = self.__tk_select_box_exam_method()
self.tk_button_search = self.__tk_button_search()
self.tk_button_export = self.__tk_button_export()
def __frame(self):
self.place(x=0, y=100, width=1000, height=500)
def __tk_table_stu_score(self):
# 表头字段 表头宽度
self.tk_table_stu_score_columns = {"#": 50, "课程名称": 200, "课程性质": 150, "开课学院": 300, "考试方式": 100, "学分": 100, "成绩": 100}
# 初始化表格 表格是基于Treeview,tkinter本身没有表格。show="headings" 为隐藏首列。
tk_table = Treeview(self, show="headings", columns=list(self.tk_table_stu_score_columns))
for text, width in self.tk_table_stu_score_columns.items(): # 批量设置列属性
tk_table.heading(text, text=text, anchor='center')
tk_table.column(text, anchor='center', width=width, stretch=False) # stretch 不自动拉伸
# 插入数据示例
# self.tk_score_table_dataset = Dao.getScoreByUid(8888)
# # 导入初始数据
# if self.tk_score_table_dataset.get("code") == 0 and self.tk_score_table_dataset.get("data"):
# for data in self.tk_score_table_dataset.get("data"):
# tk_table.insert('', END, values=list(data.values()))
tk_table.place(x=0, y=55, width=1000, height=420)
return tk_table
def __tk_button_analysis(self):
btn = Button(self, text="分析")
btn.place(x=65, y=10, width=75, height=30)
return btn
def __tk_select_box_course_nature(self):
cb = Combobox(self, state="readonly")
values = ["请选择课程性质"]
for i in Dao.getDataDictByType("nature").get("data"):
values.append(i.get("v"))
cb['values'] = values
cb.current(0)
cb.place(x=180, y=10, width=150, height=30)
return cb
def __tk_select_box_course_department(self):
cb = Combobox(self, state="readonly")
values = ["请选择开课学院"]
for i in Dao.getAllDepartments().get("data"):
values.append(i.get("v"))
cb['values'] = values
cb.current(0)
cb.place(x=370, y=10, width=150, height=30)
return cb
def __tk_select_box_exam_method(self):
cb = Combobox(self, state="readonly")
values = ["请选择考试方式"]
for i in Dao.getDataDictByType("exammethod").get("data"):
values.append(i.get("v"))
cb['values'] = values
cb.current(0)
cb.place(x=560, y=10, width=150, height=30)
return cb
def __tk_button_search(self):
btn = Button(self, text="搜索")
btn.place(x=750, y=10, width=75, height=30)
return btn
def __tk_button_export(self):
btn = Button(self, text="导出")
btn.place(x=840, y=10, width=75, height=30)
return btn
class Frame_content_3(Frame):
def __init__(self, parent):
super().__init__(parent)
self.__frame()
self.tk_label_original_password = self.__tk_label_original_password()
self.tk_input_original_password = self.__tk_input_original_password()
self.tk_label_new_password = self.__tk_label_new_password()
self.tk_input_new_password = self.__tk_input_new_password()
self.tk_label_confirm_password = self.__tk_label_confirm_password()
self.tk_input_confirm_password = self.__tk_input_confirm_password()
self.tk_button_update_stu_password = self.__tk_button_update_stu_password()
def __frame(self):
self.place(x=0, y=100, width=1000, height=500)
def __tk_label_original_password(self):
label = Label(self, text="原密码", anchor="e")
label.place(x=360, y=40, width=100, height=30)
return label
def __tk_input_original_password(self):
ipt = Entry(self, show='*')
ipt.place(x=490, y=40, width=150, height=30)
return ipt
def __tk_label_new_password(self):
label = Label(self, text="新密码", anchor="e")
label.place(x=360, y=110, width=100, height=30)
return label
def __tk_input_new_password(self):
ipt = Entry(self, show='*')
ipt.place(x=490, y=110, width=150, height=30)
return ipt
def __tk_label_confirm_password(self):
label = Label(self, text="确认密码", anchor="e")
label.place(x=360, y=180, width=100, height=30)
return label
def __tk_input_confirm_password(self):
ipt = Entry(self, show='*')
ipt.place(x=490, y=180, width=150, height=30)
return ipt
def __tk_button_update_stu_password(self):
btn = Button(self, text="修改")
btn.place(x=460, y=250, width=100, height=30)
return btn
class Win(WinGUI):
def __init__(self, current_user):
super().__init__()
self.__event_bind()
self.uid = current_user.get("uid")
self.uclid = current_user.get("uclid")
self.tk_label_current_user['text'] = "当前用户:" + current_user.get("uname")
self.tk_tabs_content.tk_tabs_content_0.student_number.set(current_user.get("uid"))
self.tk_tabs_content.tk_tabs_content_0.student_name.set(current_user.get("uname"))
self.tk_tabs_content.tk_tabs_content_0.tk_tk_select_stu_gender.current(0 if current_user.get("ugender") == '男' else 1)
self.tk_tabs_content.tk_tabs_content_0.student_identify.set(current_user.get("uidentify"))
self.tk_tabs_content.tk_tabs_content_0.student_email.set(current_user.get("uemail"))
# 插入数据示例
self.score_table_dataset = Dao.getScoreByUid(self.uid)
# 导入初始数据
if self.score_table_dataset.get("code") == 0 and self.score_table_dataset.get("data"):
for data in self.score_table_dataset.get("data"):
self.tk_tabs_content.tk_tabs_content_1.tk_table_stu_score.insert('', END, values=list(data.values()))
def logout(self):
messagebox.showwarning('提示', '欢迎下次使用!')
self.destroy()
login = Login.Win()
login.mainloop()
def updateStudentInfo(self, evt):
__stu_name = self.tk_tabs_content.tk_tabs_content_0.tk_input_stu_name.get()
__stu_gender = self.tk_tabs_content.tk_tabs_content_0.tk_tk_select_stu_gender.get()
__stu_identify = self.tk_tabs_content.tk_tabs_content_0.tk_input_stu_identity.get()
__stu_email = self.tk_tabs_content.tk_tabs_content_0.tk_input_stu_email.get()
if not __stu_name or not __stu_gender or not __stu_identify or not __stu_email:
messagebox.showinfo("提示", "必填项不能为空!")
return
if not re.match(r'^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$', __stu_identify):
messagebox.showinfo("提示", "身份证格式不合法!")
return
if not re.match(r'^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$', __stu_email):
messagebox.showinfo("提示", "电子邮箱格式不合法!")
return
res = Dao.updateUser(self.uid, __stu_name, __stu_gender, __stu_identify, self.uclid, __stu_email)
messagebox.showinfo("提示", res.get("msg"))
self.tk_label_current_user['text'] = "当前用户:" + __stu_name
print("更新学生信息", evt)
def stu_reset(self, evt):
self.tk_tabs_content.tk_tabs_content_0.student_number.set(self.userInfo[0])
self.tk_tabs_content.tk_tabs_content_0.student_name.set(self.userInfo[1])
self.tk_tabs_content.tk_tabs_content_0.tk_tk_select_stu_gender.current(0 if self.userInfo[2] else 1)
self.tk_tabs_content.tk_tabs_content_0.student_identify.set(self.userInfo[3])
self.tk_tabs_content.tk_tabs_content_0.student_email.set(self.userInfo[5])
def analysisStudentScore(self, evt):
result = Dao.getScoreByUid(self.uid).get("data")
plt.title('成绩统计图')
# 设置x轴数据
x = [i.get("cname") for i in result]
# 每组数据n有3个类型
total_width, n = 0.6, 3
width = total_width / n
y1 = [i.get("score") for i in result]
y2 = [i.get("avg_score") for i in Dao.getAllCourseAvgScore(self.uid).get("data")]
plt.bar(x, y1, color="b", width=width, label='我的成绩')
plt.plot(x, y2, color="g", label='科目平均成绩')
# x和y轴标题
plt.xlabel("课程")
plt.ylabel("分数")
plt.legend(loc="best")
plt.ylim((0, 100))
# 设置纵轴起始,终止和间距
my_y_ticks = np.arange(0, 100, 10)
plt.yticks(my_y_ticks)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 支持中文显示
plt.show()
print("成绩分析图表绘制")
def searchStudentScore(self, evt):
__score_query = self.tk_tabs_content.tk_tabs_content_1
__nature = __score_query.tk_select_box_course_nature.get()
__department = __score_query.tk_select_box_course_department.get()
__exammethod = __score_query.tk_select_box_exam_method.get()
if __score_query.tk_select_box_course_nature.current() == 0:
__nature = ''
if __score_query.tk_select_box_course_department.current() == 0:
__department = ''
if __score_query.tk_select_box_exam_method.current() == 0:
__exammethod = ''
for _ in map(__score_query.tk_table_stu_score.delete, __score_query.tk_table_stu_score.get_children("")):
pass
self.score_table_dataset = Dao.getScoreByUid(self.uid, __nature, __department, __exammethod)
# 导入初始数据
if self.score_table_dataset.get("code") == 0 and self.score_table_dataset.get("data"):
for data in self.score_table_dataset.get("data"):
__score_query.tk_table_stu_score.insert('', END, values=list(data.values()))
__score_query.tk_select_box_course_nature.current(0)
__score_query.tk_select_box_course_department.current(0)
__score_query.tk_select_box_exam_method.current(0)
print(f"查询学生{self.uid}的成绩!")
def exportStudentScore(self, evt):
path = filedialog.askdirectory()
try:
book = openpyxl.Workbook()
sheet = book.active
fff = list(self.tk_tabs_content.tk_tabs_content_1.tk_table_stu_score_columns.keys()) # 获取表头信息
sheet.append(fff)
dataset = [list(data_item.values()) for data_item in
self.score_table_dataset.get("data")]
print(dataset)
for i in dataset:
sheet.append(i)
book.save(f"{path}/{self.uid}.xlsx")
messagebox.showinfo("提示", "导出成功!")
except Exception as e:
messagebox.showinfo("提示", "导出失败!")
print(e)
print("事件未处理", evt)
def updateStudentPassword(self, evt):
__original_pwd = self.tk_tabs_content.tk_tabs_content_3.tk_input_original_password.get()
__new_pwd = self.tk_tabs_content.tk_tabs_content_3.tk_input_new_password.get()
__confirm_pwd = self.tk_tabs_content.tk_tabs_content_3.tk_input_confirm_password.get()
if __original_pwd == '' or __new_pwd == '' or __confirm_pwd == '':
messagebox.showwarning("提示", "必填项未填写!")
return
if not re.match(r"^[0-9a-zA-Z~!@#$%^&*._?]{6,18}$", __original_pwd) \
or not re.match(r"^[0-9a-zA-Z~!@#$%^&*._?]{6,18}$", __new_pwd) \
or not re.match(r"^[0-9a-zA-Z~!@#$%^&*._?]{6,18}$", __confirm_pwd):
messagebox.showwarning("提示", "密码格式应为6-18位数字、字母、特殊字符的组合!")
return
if __new_pwd != __confirm_pwd:
messagebox.showwarning("提示", "两次密码输入不一致")
return
res = Dao.updatePassword(self.uid, __original_pwd, __new_pwd)
messagebox.showinfo("提示", res.get("msg"))
if res.get("code") == 0:
self.destroy()
login = Login.Win()
login.mainloop()
print("修改密码", evt)
def logout_user(self, evt):
messagebox.showwarning('提示', '欢迎下次使用!')
self.destroy()
login = Login.Win()
login.mainloop()
def __event_bind(self):
self.protocol('WM_DELETE_WINDOW', self.logout)
self.tk_tabs_content.tk_tabs_content_0.tk_button_stu_update.bind('', self.updateStudentInfo)
self.tk_tabs_content.tk_tabs_content_0.tk_button_stu_reset.bind('', self.stu_reset)
self.tk_tabs_content.tk_tabs_content_1.tk_button_analysis.bind('', self.analysisStudentScore)
self.tk_tabs_content.tk_tabs_content_1.tk_button_search.bind('', self.searchStudentScore)
self.tk_tabs_content.tk_tabs_content_1.tk_button_export.bind('', self.exportStudentScore)
self.tk_tabs_content.tk_tabs_content_3.tk_button_update_stu_password.bind('',
self.updateStudentPassword)
self.tk_button_logout.bind('', self.logout_user)
数据库采用mysql 8.0,库名和表如下:
Dao层代码如下:用于访问数据库,向数据库发送sql语句,完成成绩与科目等增删改查任务
Dao.py:
import pymysql
def getConnect():
"""
获取数据库连接
:return:
"""
conn = pymysql.Connect(
host='localhost',
port=3306,
user='#你的数据库用户名',
password='#你的数据库密码',
db='stu_sc_sys',
charset='utf8',
cursorclass=pymysql.cursors.DictCursor
)
cursor = conn.cursor()
return conn, cursor
def getUserByIdAndPwd(username, password):
conn, cursor = getConnect()
sql = f"select uid, uname, ugender, uidentify, uclid, uemail, urole from user where uid='{username}' " \
f"and upwd='{password}'"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchone()
}
cursor.close()
conn.close()
return res
def getUserInfoById(uid):
conn, cursor = getConnect()
sql = f"select uid, uname, ugender, uidentify, uclid, uemail, urole from user where uid='{uid}'"
cursor.execute(sql)
res = cursor.fetchone()
cursor.close()
conn.close()
return res
def updatePassword(uid, origin_pwd, new_pwd):
conn, cursor = getConnect()
res = {
"code": 1,
"msg": "修改密码失败!"
}
if not getUserByIdAndPwd(uid, origin_pwd).get("data"):
res = {
"code": 1,
"msg": "原密码不正确!"
}
else:
sql = f"update user set upwd = '{new_pwd}' where uid = '{uid}'"
try:
cursor.execute(sql)
conn.commit()
res = {
"code": 0,
"msg": "修改成功!"
}
except Exception as e:
conn.rollback()
print(e)
return res
def getScoreByUid(uid, nature='', department='', exam_method=''):
"""
通过学号获取成绩
:param uid:
:param nature:
:param department:
:param exam_method:
:return:
"""
conn, cursor = getConnect()
sql = f"select ROW_NUMBER() over () as id, uc.cname, c.cnature, c.cdepartment, c.cexammethod, c.ccredit, score " \
f"from user_course uc inner join user u on uc.uid = u.uid inner join course c on uc.cname = c.cname " \
f"where u.uid = '{uid}' and c.cnature like '%{nature}%' and " \
f"c.cdepartment like '%{department}%' and c.cexammethod like '%{exam_method}%'"
print(sql)
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
conn.close()
return res
def getAllUsers():
connection, cursor = getConnect()
sql = 'select uid, uname, ugender, uidentify, uclid, uemail, upwd, urole from user'
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def getAllStudents():
connection, cursor = getConnect()
sql = "select row_number() over () as id, uid, uname, ugender, uidentify, uclid, uemail from user where urole = 1"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def searchStudents(uname, ugender):
"""
学生信息搜索
:param uname:
:param ugender:
:return:
"""
connection, cursor = getConnect()
sql = f"select row_number() over () as id, uid, uname, ugender, uidentify, uclid, uemail, upwd, urole from user " \
f"where urole = 1 and uname like '%{uname}%' and ugender like '%{ugender}%'"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def addStudent(uid, uname, ugender, uidentify, uclid, uemail):
"""
添加一个学生信息,密码默认为123456
:param uid:
:param uname:
:param ugender:
:param uidentify:
:param uclid:
:param uemail:
:return:
"""
connection, cursor = getConnect()
sql = f"insert into user(uid, uname, ugender, uidentify, uclid, uemail, upwd) values ('{uid}', '{uname}'" \
f", '{ugender}', '{uidentify}', '{uclid}', '{uemail}', '123456') "
res = {
"code": 0,
"msg": "添加成功!"
}
try:
cursor.execute(sql)
connection.commit()
except Exception as e:
res = {
"code": 1,
"msg": "添加失败!"
}
connection.rollback()
print(e)
cursor.close()
connection.close()
return res
def deleteUser(uid):
"""
通过uid删除用户
:param uid:
:return:
"""
connection, cursor = getConnect()
sql = f"delete from user where uid = '{uid}'"
res = {
"code": 0,
"msg": "删除成功!"
}
try:
cursor.execute(sql)
connection.commit()
except Exception as e:
res = {
"code": 1,
"msg": "删除失败!"
}
connection.rollback()
print(e)
cursor.close()
connection.close()
return res
def updateUser(uid, uname, ugender, uidentify, uclid, uemail):
"""
通过uid更新用户信息
:param uid:
:param uname:
:param ugender:
:param uidentify:
:param uclid:
:param uemail:
:return:
"""
connection, cursor = getConnect()
sql = f"update user set uname = '{uname}', ugender = '{ugender}', uidentify = '{uidentify}', uclid = '{uclid}'" \
f", uemail ='{uemail}' where uid = '{uid}'"
print(sql)
res = {
"code": 0,
"msg": "修改成功!"
}
try:
cursor.execute(sql)
connection.commit()
except Exception as e:
res = {
"code": 1,
"msg": "修改失败!"
}
connection.rollback()
print(e)
cursor.close()
connection.close()
return res
def getAllCourses():
"""
获取所有的课程信息
:return:
"""
connection, cursor = getConnect()
sql = "select cid, cname, ccredit, cnature, cdepartment, cexammethod from course"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def getCourseByCid(cid):
"""
获取cid的课程
:return:
"""
connection, cursor = getConnect()
sql = f"select cid, cname, cnature, ccredit, cdepartment, cexammethod from course where cid = '{cid}'"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def getDataDictByType(dtype):
"""
获取dtype类型的数据字典
:param:
:return:
"""
connection, cursor = getConnect()
sql = f"select d.ddtkey as k, d.ddtvalue as v from dictionary d where d.ddtype = '{dtype}'"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def getAllDepartments():
"""
获取所有的学院
:return:
"""
connection, cursor = getConnect()
sql = "select did as k, dname as v from department"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def getMaxStuNumber(s_num_prefix):
"""
获取以s_num_prefix开头的最大学号
:return:
"""
connection, cursor = getConnect()
sql = f"select MAX(uid) as max_id from user where uid like '{s_num_prefix}%'"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def addCourse(cname, nature, credit, department, exam_method):
"""
添加课程
:return:
"""
connection, cursor = getConnect()
sql = f"insert into course(cname, cnature, ccredit, cdepartment, cexammethod) VALUES ('{cname}', '{nature}'" \
f", '{credit}', '{department}', '{exam_method}')"
res = {
"code": 0,
"msg": "添加课程成功!"
}
try:
cursor.execute(sql)
connection.commit()
except Exception as e:
res = {
"code": 1,
"msg": "添加课程失败!"
}
connection.rollback()
print(e)
cursor.close()
connection.close()
return res
def deleteCourse(cid):
"""
删除课程
:return:
"""
connection, cursor = getConnect()
sql = f"delete from course where cid = {cid}"
res = {
"code": 0,
"msg": "删除课程成功!"
}
try:
cursor.execute(sql)
connection.commit()
except Exception as e:
res = {
"code": 1,
"msg": "删除课程失败!"
}
connection.rollback()
print(e)
cursor.close()
connection.close()
return res
def searchCourses(department, exammethod):
"""
搜索课程信息
:param department:
:param exammethod:
:return:
"""
connection, cursor = getConnect()
sql = f"select cid, cname, ccredit, cnature, cdepartment, cexammethod from course " \
f"where cdepartment like '%{department}%' and cexammethod like '%{exammethod}%'"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def updateCourseInfo(cid, cname, nature, credit, department, exammethod):
"""
修改课程信息
:param cid:
:param cname:
:param nature:
:param credit:
:param department:
:param exammethod:
:return:
"""
connection, cursor = getConnect()
sql = f"update course set cname = '{cname}', cnature = '{nature}', ccredit = '{credit}'" \
f", cdepartment = '{department}', cexammethod = '{exammethod}' where cid = '{cid}'"
res = {
"code": 0,
"msg": "修改课程成功!"
}
try:
cursor.execute(sql)
connection.commit()
except Exception as e:
res = {
"code": 1,
"msg": "更新课程失败!"
}
connection.rollback()
print(e)
cursor.close()
connection.close()
return res
def getScoreBandByCName(course_name):
"""
获取课程名为course_name的各个分段的学生人数
:param course_name:
:return:
"""
connection, cursor = getConnect()
sql = f"select SUM(IF(score <= 100 and score >= 90, 1, 0)) as A, SUM(IF(score < 90 and score >= 80, 1, 0)) as B, " \
f"SUM(IF(score < 80 and score >= 70, 1, 0)) as C, SUM(IF(score < 70 and score >= 60, 1, 0)) as D, " \
f"SUM(IF(score < 60, 1, 0)) as E from user_course where cname = '{course_name}'"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def getMaxAndMinAndAvgScoreByCLid(class_id):
"""
获取班级号为class_id的班级的各科最高分、最低分以及平均分
:param class_id:
:return:
"""
connection, cursor = getConnect()
sql = f"select uc.cname, MAX(score) as max_score, MIN(score) as min_score, AVG(score) as avg_score " \
f"from user_course uc inner join user u on uc.uid = u.uid where u.uclid = '{class_id}' group by uc.cname"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def getOverallGradeLevelByCLid(class_id):
"""
获取班级号为class_id的班级综合成绩等级各分段人数
:param class_id:
:return:
"""
connection, cursor = getConnect()
sql = f"select SUM(IF(avg_score >= 85 and avg_score <= 100, 1, 0)) as A, " \
f"SUM(IF(avg_score >= 70 and avg_score < 85, 1, 0)) as B, " \
f"SUM(IF(avg_score >= 60 and avg_score < 70, 1, 0)) as C, " \
f"SUM(IF(avg_score < 60, 1, 0)) as D from (" \
f"select AVG(score) as avg_score from user_course uc " \
f"inner join user u on uc.uid = u.uid where u.uclid = '{class_id}' group by u.uid" \
f") s"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def getAllClasses():
"""
获取用户表中已存在的班级号
:return:
"""
connection, cursor = getConnect()
sql = f"select distinct uclid from user where urole = 1"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def getAllCourseAvgScore(uid):
"""
获取所有课程的平均分
:return:
"""
connection, cursor = getConnect()
sql = f"select cname, AVG(score) as avg_score from user_course where cname in " \
f"(select cname from user_course where uid = '{uid}') group by cname"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def searchStudentScore(course_name='', course_nature='', course_department=''):
"""
搜索学生成绩
:param course_name:
:param course_nature:
:param course_department:
:return:
"""
connection, cursor = getConnect()
sql = f"select ROW_NUMBER() over () as id, u.uid, u.uname, uc.cname, c.cnature, c.cdepartment, c.cexammethod, " \
f"c.ccredit, score from user_course uc inner join user u on uc.uid = u.uid inner join course c " \
f"on uc.cname = c.cname where c.cname like '%{course_name}%' and " \
f"c.cnature like '%{course_nature}%' and c.cdepartment like '%{course_department}%'"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def getScoreByUidAndCName(uid, course_name):
"""
查找学号为uid课程为course_name的学生成绩
:param uid:
:param course_name:
:return:
"""
connection, cursor = getConnect()
sql = f"select uid, cname, score from user_course where uid = '{uid}' and cname = '{course_name}'"
cursor.execute(sql)
res = {
"code": 0,
"msg": "success",
"data": cursor.fetchall()
}
cursor.close()
connection.close()
return res
def addStudentScore(uid, course_name, score):
connection, cursor = getConnect()
if not cursor.execute(f"select uid from user where uid = '{uid}'"):
return {
"code": 1,
"msg": "学号不存在!"
}
if cursor.execute(f"select 1 from user_course where uid = '{uid}' and cname = '{course_name}' limit 1"):
return {
"code": 1,
"msg": f"该学生的{course_name}课程成绩已经存在!"
}
sql = f"insert into user_course(uid, cname, score) VALUES ('{uid}', '{course_name}', '{score}')"
res = {
"code": 0,
"msg": "添加成绩成功!"
}
try:
cursor.execute(sql)
connection.commit()
except Exception as e:
res = {
"code": 1,
"msg": "添加成绩失败!"
}
connection.rollback()
print(e)
cursor.close()
connection.close()
return res
def deleteStudentScore(uid, course_name):
connection, cursor = getConnect()
if not cursor.execute(f"select uid from user where uid = '{uid}'"):
return {
"code": 1,
"msg": "学号不存在!"
}
sql = f"delete from user_course where uid = '{uid}' and cname = '{course_name}'"
res = {
"code": 0,
"msg": "删除成绩成功!"
}
try:
code = cursor.execute(sql)
connection.commit()
if code == 0:
res = {
"code": 0,
"msg": f"该学生的{course_name}课程成绩不存在!"
}
except Exception as e:
res = {
"code": 1,
"msg": "删除成绩失败!"
}
connection.rollback()
print(e)
cursor.close()
connection.close()
return res
def updateStudentScore(uid, course_name, score):
connection, cursor = getConnect()
sql = f"update user_course set score = '{score}' where uid = '{uid}' and cname = '{course_name}'"
res = {
"code": 0,
"msg": "修改成绩成功!"
}
try:
cursor.execute(sql)
connection.commit()
except Exception as e:
res = {
"code": 1,
"msg": "修改成绩失败!"
}
connection.rollback()
print(e)
cursor.close()
connection.close()
return res