学生成绩管理系统

  • 1. 标准模块导入
  • 2.完整代码
  • 3.文件保存模块

作者:潇
版本:1.0
面向对象,带日志,带异常处理的,带密码加密
第一次执行会生成数据库和csv文件,以后添加的数据会自动保存到里面
删除数据库再次执行程序。会初始化数据库


2022-10-28更新:

  • 关于部分读者不知道登录密码的问题,本系统在设计时采用了一个超级账户,即在DataProcess.py的AdScProcess函数中定义了如下数组
Admins = [['admin', 'admin']]
  • 由此保证一定有一个用户可以登录
  • 在首次登录过程中,因为系统中仍没有学生信息,所以只能先通过这个账户登录管理系统进行操作

1. 标准模块导入

from tkinter import *
from tkinter import messagebox
from tkinter import ttk
import time

2.完整代码

  • 本段为系统主代码,文件名自定义即可,最后在本文件运行系统
# _*_ coding:utf-8 _*_
"""
@ 功能 : 本模块用于对窗口界面的定义
@ author : 王子潇
@ create : 2020/7
"""
from tkinter import *
from tkinter import messagebox
from tkinter import ttk
import DataProcess as Dp
import timeclass FirstFrame(Frame):"""程序首界面,用于选择执行的系统"""global Student   # 存放学生信息的列表def __init__(self, master=None):super().__init__(master)  # super()代表了父类的定义self.master = masterself.pack(anchor='n')  # 创建frame时将其放置在master父模块上'''建造时创建组件'''# 初始化组件的属性self.label_tit = Label(self, text='学生成绩系统', width=24, height=1, fg='black', font=('黑体', 25))self.btn_stu = Button(self, text='学生成绩查询系统', width=18, height=1, bg='gray', font=('黑体', 15))self.btn_adm = Button(self, text='学生成绩管理系统', width=18, height=1, bg='gray', font=('黑体', 15))self.btnQuit = Button(self, text='退出', width=18, height=1, font=('黑体', 15), command=Exit)# 组件的放置位置self.label_tit.grid(row=0, column=2, columnspan=3, pady=30)self.btn_stu.grid(row=1, column=0, columnspan=3, pady=30, padx=50)self.btn_adm.grid(row=1, column=4, columnspan=3, pady=30, padx=50)self.btnQuit.grid(row=2, column=2, columnspan=3, pady=30)# 组件和事件的绑定self.btn_stu.bind('<Button-1>', self.btn_stu_ev)self.btn_adm.bind('<Button-1>', self.btn_adm_ev)def btn_stu_ev(self, event):"""学生成绩查询系统 的操作"""global rootRegisterFrame(master=root, TypeChoice='Student')self.destroy()def btn_adm_ev(self, event):"""学生成绩管理系统 的操作"""global rootRegisterFrame(master=root, TypeChoice='Admin')self.destroy()class RegisterFrame(Frame):"""登录界面"""def __init__(self, master=None, TypeChoice=None):  # TypeChoice 用于判断学生查询界面或管理员登录界面super().__init__(master)  # super()代表了父类的定义self.master = masterself.type = TypeChoiceself.Save = 0self.pack(anchor='center')  # 创建时将Frame放置在master中if self.type == 'Student':self.type = '学生成绩查询系统登录界面'elif self.type == 'Admin':self.type = '学生成绩管理系统登录界面'else:self.type = '登陆界面函数参数错误'  # 通过判断 self.type 的值决定界面的标题抬头"""创建组件"""# 初始化组件的属性self.label_tit = Label(self, text=self.type, width=24, height=1, fg='black', font=('黑体', 20))self.label_adm = Label(self, text='用户名(姓名):', width=12, height=1, fg='black', font=('黑体', 15))self.label_pwd = Label(self, text='密  码(学号):', width=12, height=1, fg='black', font=('黑体', 15))self.btn_cfm = Button(self, text='确定', width=8, height=1, bg='gray', font=('黑体', 15))self.btn_cnc = Button(self, text='清空', width=8, height=1, bg='gray', font=('黑体', 15))self.btn_rtn = Button(self, text='返回', width=8, height=1, bg='gray', font=('黑体', 15))self.btnQuit = Button(self, text='退出系统', width=8, height=1, font=('黑体', 15), command=Exit)self.adm = StringVar()  # 将Entry框的内容与变量进行绑定self.pwd = StringVar()self.adm.set('admin')  # 设定Entry框显示的内容self.pwd.set('')self.entry_adm = Entry(self, textvariable=self.adm)self.entry_pwd = Entry(self, textvariable=self.pwd, show='*')# 设定组件在父Frame 中的位置self.label_tit.grid(row=0, column=0, columnspan=48, pady=30)self.label_adm.grid(row=1, column=0, pady=20, columnspan=12, sticky=W)self.label_pwd.grid(row=2, column=0, pady=20, columnspan=12, sticky=W)self.btn_cfm.grid(row=3, column=0, pady=20, padx=20, columnspan=8)self.btn_cnc.grid(row=3, column=10, pady=20, padx=20, columnspan=8)self.btn_rtn.grid(row=3, column=20, pady=20, padx=20, columnspan=8)self.btnQuit.grid(row=4, column=10, pady=20, columnspan=8)self.entry_adm.grid(row=1, column=20, columnspan=12, )self.entry_pwd.grid(row=2, column=20, columnspan=12, )# 设定组件绑定的事件self.btn_cfm.bind('<Button-1>', self.btn_cfm_ev)self.btn_cnc.bind('<Button-1>', self.btn_cnc_ev)self.btn_rtn.bind('<Button-1>', self.btn_rtn_ev)self.entry_adm.bind('<KeyPress-Return>', self.btn_cfm_ev)self.entry_pwd.bind('<KeyPress-Return>', self.btn_cfm_ev)def btn_cfm_ev(self, event):"""确认按钮对应的事件"""global Admin, School, root, Empty, Student, adMenuFrame, showFrame, FindResult, findStudentif self.type == '学生成绩管理系统登录界面' and [self.adm.get(), self.pwd.get()] in Admin:  # 当在管理员登陆界面并且账号密码在管理员列表中if School.get('name') is None:  # 如果学校信息元组为空时,对学校信息进行初始化messagebox.showinfo(title='提示信息', message='请初始化学校信息!')self.destroy()StudentSet(master=root)else:  # 转入管理员界面self.destroy()Empty.destroy()adMenuFrame = AdMenuFrame(master=root)showFrame = ShowFrame(master=root)elif self.adm.get() == '':  # 账号Entry框为空messagebox.showinfo(title='提示信息', message='账号(姓名)不能为空!')elif self.type == '学生成绩查询系统登录界面' and self.pwd.get() == '':messagebox.showinfo(title='提示信息', message='密码(学号)不能为空!')elif self.type == '学生成绩查询系统登录界面' and self.pwd.get() != '':for i in range(1, len(Student)):  # 学生成绩查询系统界面 判断学生姓名和学号是否存在并对应同一个人if self.pwd.get() == Student[i][0] and self.adm.get() == Student[i][1]:self.Save = iif self.Save != 0:FindResult = Student[self.Save]self.destroy()Empty.destroy()findStudent = FindStudent(master=root)else:messagebox.showinfo(title='提示信息', message='姓名或学号输入错误,不存在该学生信息!')else:messagebox.showinfo(title='提示信息', message='账号或密码输入错误!')def btn_cnc_ev(self, event):"""清空按钮对应的事件"""self.adm.set('')self.pwd.set('')def btn_rtn_ev(self, event):"""返回按钮对应的事件"""global rootself.destroy()FirstFrame(master=root)class StudentSet(Frame):"""学校信息初始化界面"""def __init__(self, master=None):super().__init__(master)  # super()代表了父类的定义self.master = masterself.pack(anchor='n')"""创建组件"""# 组件内容的初始化self.label_tit = Label(self, text='学校信息初始化', width=24, height=1, fg='black', font=('黑体', 25))self.label_scn = Label(self, text='学  校名称:', width=12, height=1, fg='black', font=('黑体', 15))self.label_C_grade = Label(self, text='C 语言学分:', width=12, height=1, fg='black', font=('黑体', 15))self.label_M_grade = Label(self, text='数  学学分:', width=12, height=1, fg='black', font=('黑体', 15))self.label_E_grade = Label(self, text='英  语学分:', width=12, height=1, fg='black', font=('黑体', 15))self.btn_cfm = Button(self, text='确定', width=8, height=1, bg='gray', font=('黑体', 15))self.btn_rtn = Button(self, text='返回上一级', width=10, height=1, bg='gray', font=('黑体', 15))self.btn_cnc = Button(self, text='清空', width=8, height=1, bg='gray', font=('黑体', 15))self.btnQuit = Button(self, text='退出系统', width=8, height=1, font=('黑体', 15), command=Exit)self.v_Name = StringVar()self.v_C_grade = StringVar()self.v_M_grade = StringVar()self.v_E_grade = StringVar()self.entry_scn = Entry(self, textvariable=self.v_Name, width=24)self.entry_C_grade = Entry(self, textvariable=self.v_C_grade, width=24)self.entry_M_grade = Entry(self, textvariable=self.v_M_grade, width=24)self.entry_E_grade = Entry(self, textvariable=self.v_E_grade, width=24)# 组件的放置位置self.label_tit.grid(row=0, column=0, columnspan=24, pady=30)self.label_scn.grid(row=1, column=0, columnspan=12)self.label_C_grade.grid(row=2, column=0, columnspan=12)self.label_M_grade.grid(row=3, column=0, columnspan=12)self.label_E_grade.grid(row=4, column=0, columnspan=12)self.btn_cfm.grid(row=5, column=0, pady=20, padx=20, columnspan=8)self.btn_cnc.grid(row=5, column=10, pady=20, padx=20, columnspan=8)self.btn_rtn.grid(row=5, column=20, pady=20, padx=20, columnspan=8)self.btnQuit.grid(row=6, column=10, pady=20, columnspan=8)self.entry_scn.grid(row=1, column=15, pady=10, columnspan=24)self.entry_C_grade.grid(row=2, column=15, pady=10, columnspan=24)self.entry_M_grade.grid(row=3, column=15, pady=10, columnspan=24)self.entry_E_grade.grid(row=4, column=15, pady=10, columnspan=24)# 组件对应的事件self.btn_cfm.bind('<Button-1>', self.btn_cfm_ev)self.btn_cnc.bind('<Button-1>', self.btn_cnc_ev)self.btn_rtn.bind('<Button-1>', self.btn_rtn_ev)def btn_cfm_ev(self, event):"""确定按钮"""global School, Empty, adMenuFrame, showFrameName = self.v_Name.get()E_grade = self.v_E_grade.get()C_grade = self.v_C_grade.get()M_grade = self.v_M_grade.get()List = [Name, E_grade, C_grade, M_grade]try:if Name == '' or E_grade == '' or C_grade == '' or M_grade == '':messagebox.showinfo(title='提示信息', message='数据不能为空!')elif 0 < float(E_grade) < 10 and 0 < float(C_grade) < 10 and 0 < float(M_grade) < 10:School['name'] = NameSchool['E_grade'] = float(E_grade)School['C_grade'] = float(C_grade)School['M_grade'] = float(M_grade)Dp.Student.setting(School)messagebox.showinfo(title='提示信息', message='初始化学校信息成功!')self.destroy()Empty.destroy()adMenuFrame = AdMenuFrame(master=root)showFrame = ShowFrame(master=root)else:messagebox.showinfo(title='提示信息', message='学分必须在 0-10 之间!')except ValueError:messagebox.showinfo(title='提示信息', message='学分必须为数字!')def btn_cnc_ev(self, event):self.v_Name.set('')self.v_E_grade.set('')self.v_M_grade.set('')self.v_C_grade.set('')def btn_rtn_ev(self, event):global rootself.destroy()FirstFrame(master=root)class AdMenuFrame(Frame):"""管理员操作界面,用于对学生信息的操作"""def __init__(self, master=None):super().__init__(master)  # super()代表了父类的定义self.master = masterself.pack(anchor='n')"""创建组件"""self.label_tit = Label(self, text='学生成绩管理系统', width=24, height=1,fg='black', font=('黑体', 25))self.btn_add = Button(self, text='新增学生信息', width=12, height=1,bg='gray', font=('黑体', 15))self.btn_del = Button(self, text='删除学生信息', width=12, height=1,bg='gray', font=('黑体', 15))self.btn_adm = Button(self, text='登录账户管理', width=12, height=1,bg='gray', font=('黑体', 15))self.btn_rtn = Button(self, text='返回主界面', width=12, height=1,bg='gray', font=('黑体', 15))self.label_tit.grid(row=0, column=8, columnspan=24)self.btn_add.grid(row=1, column=0, pady=10, columnspan=12)self.btn_del.grid(row=1, column=12, pady=10, columnspan=12)self.btn_adm.grid(row=1, column=24, pady=10, columnspan=12)self.btn_rtn.grid(row=2, column=12, pady=10, columnspan=12)self.btn_add.bind('<Button-1>', self.btn_add_ev)self.btn_del.bind('<Button-1>', self.btn_del_ev)self.btn_adm.bind('<Button-1>', self.btn_adm_ev)self.btn_rtn.bind('<Button-1>', self.btn_rtn_ev)def btn_add_ev(self, event):global root, showFrame, Emptyself.destroy()showFrame.destroy()Empty = Frame(root, height=100)Empty.pack()AddStudent(master=root)def btn_del_ev(self, event):global root, showFrameself.destroy()showFrame.destroy()DelStudent(master=root)def btn_adm_ev(self, event):global root, adminSetFrame, Emptyself.destroy()showFrame.destroy()Empty = Frame(root, height=100)Empty.pack()adminSetFrame = AdminSetFrame(master=root)def btn_rtn_ev(self, event):global showFrame, Emptyself.destroy()showFrame.destroy()Empty = Frame(root, height=100)Empty.pack()FirstFrame(master=root)class ShowFrame(Frame):"""将学生信息以表格形式显示"""def __init__(self, master=None):super().__init__(master)  # super()代表了父类的定义self.master = masterself.place(relx=0.1, y=150, relwidth=0.8, height=330)"""创建组件"""global Student, countcount = len(Student)columns = Student[0]self.widths = [100, 60, 60, 60, 60, 60, 60, 60, 90]self.canvas = Canvas(self, bg='blue')  # 创建canvasself.canvas.place(relx=0, y=30, relwidth=1, relheight=1)self.treeview = ttk.Treeview(self.canvas, show="headings", columns=columns)  # 表格self.treeview.place(relx=0, rely=0, relwidth=0.97, relheight=1)self.VScroll1 = Scrollbar(self.canvas, orient='vertical', command=self.treeview.yview)self.VScroll1.place(relx=0.97, rely=0, relwidth=0.03, height=300)self.treeview.configure(yscrollcommand=self.VScroll1.set)  # 给treeview添加配置for i in range(len(self.widths)):self.treeview.column(columns[i], width=self.widths[i], anchor='center')  # 表示列,不显示self.treeview.heading(columns[i], text=columns[i])  # 显示表头for i in range(len(Student) - 1):  # 写入数据self.treeview.insert('', i, values=Student[i + 1])self.entry = 1self.treeview.bind('<Double-1>', self.set_cell_value)  # 双击左键进入编辑self.btn_new = ttk.Button(self, text='新建学生信息', width=20, command=self.NewRow)self.btn_new.place(x=50, y=0)for col in columns:  # 绑定函数,使表头可排序self.treeview.heading(col, text=col,command=lambda _col=col: self.treeview_sort_column(self.treeview, _col, False))def treeview_sort_column(self, treeview, col, reverse):  # 'Treeview' 、列名、排列方式sort = [(treeview.set(k, col), k) for k in treeview.get_children('')]sort.sort(reverse=reverse)  # 排序方式# rearrange items in sorted positionsfor index, (val, k) in enumerate(sort):  # 根据排序后索引移动treeview.move(k, '', index)treeview.heading(col, command=lambda: self.treeview_sort_column(treeview, col, not reverse))  # 重写标题,使之成为再点倒序的标题def set_cell_value(self, event):  # 双击进入编辑状态if self.entry == 0:self.entryedit.destroy()self.okb.destroy()for self.item in self.treeview.selection():# item = I001self.item_text = self.treeview.item(self.item, "values")self.items = self.item# print(self.item_text[0:])  # 输出所选行的值self.column = self.treeview.identify_column(event.x)  # 列self.row = self.treeview.identify_row(event.y)  # 行self.cn = int(str(self.column).replace('#', ''))self.rn = int(eval(str(self.row).replace('I', '0X').lower()))self.VScroll1Place = [round(list(self.VScroll1.get())[0], 2), round(list(self.VScroll1.get())[1], 2)]if self.cn <= 6:self.v_entryedit = StringVar()self.entryedit = Entry(self.treeview, textvariable=self.v_entryedit, width=12)self.okb = ttk.Button(self.treeview, text='OK', width=4)if self.rn < len(Student):self.v_entryedit.set(str(Student[self.rn][self.cn - 1]))else:self.v_entryedit.set(str(Student[0][self.cn - 1]))self.entry = x = 0for i in range(self.cn - 1):x += self.widths[i]if self.VScroll1Place[0] != 0:self.entryedit.place(x=x, y=self.rn * 20 + 5 - count * 20 * self.VScroll1Place[0])self.okb.place(x=x + 85, y=self.rn * 20 + 5 - count * 20 * self.VScroll1Place[0])else:self.entryedit.place(x=x, y=self.rn * 20 + 5)self.okb.place(x=x + 85, y=self.rn * 20 + 5)self.entryedit.bind('<KeyPress-Return>', self.save_edit)self.okb.bind('<Button-1>', self.save_edit)else:messagebox.showinfo(title='提示信息', message='该数据不能直接修改!')def save_edit(self, event):global Student, showFrameif self.rn < len(Student) and self.judge():Student[self.rn][self.cn - 1] = self.entryedit.get()if [i for i in range(3, 6) if Student[self.rn][i] != Student[0][i]] == [3, 4, 5]:Student[self.rn] = Dp.Student.append(Student[self.rn][0:6])elif self.rn >= len(Student) and self.judge():Student.append(list(Student[0]))Student[-1][self.cn - 1] = self.entryedit.get()if [i for i in range(3, 6) if Student[self.rn][i] != Student[0][i]] == [3, 4, 5]:Student[self.rn] = Dp.Student.append(Student[self.rn][0:6])self.destroy()showFrame = ShowFrame(master=root)self.entryedit.destroy()self.okb.destroy()def judge(self):try:if self.entryedit.get() == '':messagebox.showinfo(title='提示信息', message='数据不能为空!')elif self.cn == 1 and len(self.entryedit.get()) != 10:messagebox.showinfo(title='提示信息', message='学号必须为 10 位!')elif self.cn == 1 and self.entryedit.get() in [Student[i][0] for i in range(1, len(Student)) ifi != self.rn]:messagebox.showinfo(title='提示信息', message='该学号已存在!')elif self.cn == 2 and self.entryedit.get() in ['男', '女']:messagebox.showinfo(title='提示信息', message='性别必须为‘男’or‘女’!')elif 3 < self.cn < 7 and 0 < float(self.entryedit.get()) < 100:return Trueelif 3 < self.cn < 7:messagebox.showinfo(title='提示信息', message='成绩必须在 0-100 之间!')else:return Trueexcept ValueError:messagebox.showinfo(title='提示信息', message='成绩必须为数字!')def NewRow(self):global count, Studentself.treeview.insert('', count, values=Student[0])count += 1self.treeview.update()self.btn_new.update()class AddStudent(Frame):def __init__(self, master=None):super().__init__(master)  # super()代表了父类的定义self.master = masterself.pack(anchor='n')"""创建组件"""self.label_tit = Label(self, text='新增学生信息', width=12, height=1, fg='black', font=('黑体', 25))self.label_Num = Label(self, text='学      号:', width=12, height=1, fg='black', font=('黑体', 15))self.label_Name = Label(self, text='姓      名:', width=12, height=1, fg='black', font=('黑体', 15))self.label_Sex = Label(self, text='性      别:', width=12, height=1, fg='black', font=('黑体', 15))self.label_Cgrade = Label(self, text='C语言成绩:', width=12, height=1, fg='black', font=('黑体', 15))self.label_Mgrade = Label(self, text='数  学成绩:', width=12, height=1, fg='black', font=('黑体', 15))self.label_Egrade = Label(self, text='英  语成绩:', width=12, height=1, fg='black', font=('黑体', 15))self.btn_cfm = Button(self, text='确定', width=12, height=1, bg='gray', font=('黑体', 15))self.btn_del = Button(self, text='清空', width=12, height=1, bg='gray', font=('黑体', 15))self.btn_rtn = Button(self, text='返回上一级', width=12, height=1, bg='gray', font=('黑体', 15))self.v_num = StringVar()self.v_name = StringVar()self.v_Cgrade = StringVar()self.v_Mgrade = StringVar()self.v_Egrade = StringVar()self.entry_Num = Entry(self, textvariable=self.v_num)self.entry_Name = Entry(self, textvariable=self.v_name)self.sexvalue = StringVar()self.sexvalue.set('男')self.sexman = Radiobutton(self, text="男", value="男", variable=self.sexvalue)self.sexwoman = Radiobutton(self, text="女", value="女", variable=self.sexvalue)self.entry_Cgrade = Entry(self, textvariable=self.v_Cgrade)self.entry_Mgrade = Entry(self, textvariable=self.v_Mgrade)self.entry_Egrade = Entry(self, textvariable=self.v_Egrade)self.label_tit.grid(row=0, column=6, columnspan=24, pady=40)self.label_Num.grid(row=1, column=0, columnspan=12)self.label_Name.grid(row=2, column=0, columnspan=12)self.label_Sex.grid(row=3, column=0, columnspan=12)self.label_Cgrade.grid(row=4, column=0, columnspan=12)self.label_Mgrade.grid(row=5, column=0, columnspan=12)self.label_Egrade.grid(row=6, column=0, columnspan=12)self.entry_Num.grid(row=1, column=18, columnspan=18)self.entry_Name.grid(row=2, column=18, columnspan=18)self.sexman.grid(row=3, column=18, columnspan=9)self.sexwoman.grid(row=3, column=27, columnspan=9)self.entry_Cgrade.grid(row=4, column=18, columnspan=18)self.entry_Mgrade.grid(row=5, column=18, columnspan=18)self.entry_Egrade.grid(row=6, column=18, columnspan=18)self.btn_cfm.grid(row=7, column=0, pady=20, padx=5, columnspan=12)self.btn_del.grid(row=7, column=12, pady=20, padx=5, columnspan=12)self.btn_rtn.grid(row=7, column=24, pady=20, padx=5, columnspan=12)self.btn_cfm.bind('<Button-1>', self.btn_cfm_ev)self.btn_del.bind('<Button-1>', self.btn_del_ev)self.btn_rtn.bind('<Button-1>', self.btn_rtn_ev)def btn_cfm_ev(self, event):global StudentAppendSet = list([self.v_num.get(), self.v_name.get(), self.sexvalue.get(), self.v_Cgrade.get(), self.v_Mgrade.get(),self.v_Egrade.get()])try:if [i for i in range(6) if AppendSet[i] != ''] != [0, 1, 2, 3, 4, 5]:messagebox.showinfo(title='提示信息', message='数据不能为空!')elif len(AppendSet[0]) != 10:messagebox.showinfo(title='提示信息', message='学号必须为 10 位!')elif AppendSet[0] in [Student[i][0] for i in range(1, len(Student))]:messagebox.showinfo(title='提示信息', message='该学号已存在!')elif int(AppendSet[0]) > 0 and 0 < float(AppendSet[3]) < 100 and 0 < float(AppendSet[4]) < 100 and 0 < float(AppendSet[5]) < 100:Student.append(Dp.Student.append(AppendSet))self.v_num.set('')self.v_name.set('')self.sexvalue.set('男')self.v_Cgrade.set('')self.v_Mgrade.set('')self.v_Egrade.set('')else:messagebox.showinfo(title='提示信息', message='成绩必须在 0-100 之间!')except BaseException:messagebox.showinfo(title='提示信息', message='学号和成绩必须为数字!')def btn_del_ev(self, event):self.v_num.set('')self.v_name.set('')self.sexvalue.set('男')self.v_Cgrade.set('')self.v_Mgrade.set('')self.v_Egrade.set('')def btn_rtn_ev(self, event):global Empty, adMenuFrame, showFrameself.destroy()Empty.destroy()adMenuFrame = AdMenuFrame(master=root)showFrame = ShowFrame(master=root)class DelStudent(Frame):"""用于删除学生信息"""def __init__(self, master=None):super().__init__(master)  # super()代表了父类的定义self.master = masterself.place(relx=0.1, relwidth=0.8, relheight=1)"""创建组件"""self.label_tit = Label(self, text='删除学生信息', width=12, height=1, fg='black', font=('黑体', 25))self.label_Num = Label(self, text='学      号:', width=12, height=1, fg='black', font=('黑体', 15))self.label_Name = Label(self, text='姓      名:', width=12, height=1, fg='black', font=('黑体', 15))self.label_Rmd = Label(self, text='支持模糊搜索,双击需要删除的行并确定', width=40, height=1, fg='black', font=('黑体', 10))self.btn_cfm = Button(self, text='确定', width=12, height=1, bg='gray', font=('黑体', 15))self.btn_del = Button(self, text='清空', width=12, height=1, bg='gray', font=('黑体', 15))self.btn_rtn = Button(self, text='返回上一级', width=12, height=1, bg='gray', font=('黑体', 15))self.v_num = StringVar()self.v_name = StringVar()self.entry_Num = Entry(self, textvariable=self.v_num)self.entry_Name = Entry(self, textvariable=self.v_name)self.label_tit.grid(row=0, column=18, columnspan=24, pady=40)self.label_Num.grid(row=1, column=12, columnspan=12)self.label_Name.grid(row=2, column=12, columnspan=12)self.label_Rmd.grid(row=8, column=12, columnspan=40)self.entry_Num.grid(row=1, column=30, columnspan=18)self.entry_Name.grid(row=2, column=30, columnspan=18)self.btn_cfm.grid(row=7, column=12, pady=20, padx=5, columnspan=12)self.btn_del.grid(row=7, column=24, pady=20, padx=5, columnspan=12)self.btn_rtn.grid(row=7, column=36, pady=20, padx=5, columnspan=12)self.btn_cfm.bind('<Button-1>', self.btn_cfm_ev)self.btn_del.bind('<Button-1>', self.btn_del_ev)self.btn_rtn.bind('<Button-1>', self.btn_rtn_ev)def FindShowFrame(self):"""用于显示查找到的学生信息"""global Studentcolumns = Student[0]widths = [100, 60, 60, 60, 60, 60, 60, 60, 90]self.canvas = Canvas(self)  # 创建canvasself.canvas.place(relx=0, y=280, relwidth=1, height=250)self.treeview = ttk.Treeview(self.canvas, show="headings", columns=columns)  # 表格self.treeview.place(relx=0, rely=0, relwidth=0.97, relheight=1)self.treeview.bind('<Double-1>', self.del_value)  # 双击左键进入删除确定self.VScroll1 = Scrollbar(self.canvas, orient='vertical', command=self.treeview.yview)self.VScroll1.place(relx=0.97, rely=0, relwidth=0.03, relheight=1)for i in range(len(widths)):self.treeview.column(columns[i], width=widths[i], anchor='center')  # 表示列,不显示self.treeview.heading(columns[i], text=columns[i])  # 显示表头for i in range(len(self.Find)):  # 写入数据self.treeview.insert('', i, values=self.Find[i])def btn_cfm_ev(self, event):global Studentself.Find = []num = name = Save = Truefor i in range(1, len(Student)):if self.v_num.get() != '' and self.v_num.get() in Student[i][0]:num = Save = Falseif self.v_name.get() != '' and self.v_name.get() in Student[i][1]:name = Save = Falseif not Save:self.Find.append(Student[i])Save = Trueself.FindShowFrame()if len(self.Find) > 1:messagebox.showinfo(title='提示信息', message='找到多个学生信息!')elif self.v_num.get() == self.v_name.get() == '':messagebox.showinfo(title='提示信息', message='请输入学生信息!')if self.v_num.get() != '' and num:messagebox.showinfo(title='提示信息', message='按“学号”不存在该生信息!')elif self.v_name.get() != '' and name:messagebox.showinfo(title='提示信息', message='按“姓名”不存在该生信息!')def btn_del_ev(self, event):self.v_num.set('')self.v_name.set('')def btn_rtn_ev(self, event):global Empty, adMenuFrame, showFrameself.destroy()adMenuFrame = AdMenuFrame(master=root)showFrame = ShowFrame(master=root)def del_value(self, event):  # 双击进行删除global Studentfor self.item in self.treeview.selection():# item = I001self.item_text = self.treeview.item(self.item, "values")self.items = self.itema = '是否删除学号为:{0},姓名为{1}的学生?'.format(self.item_text[0], self.item_text[1])res = messagebox.askokcancel(title='提示消息', message=a)if res == True:for i in range(1, len(Student)):if list(self.item_text[0:]) == Student[i]:del Student[i]for i in range(len(self.Find)):if list(self.item_text[0:]) == self.Find[i]:del self.Find[i]self.canvas.destroy()self.FindShowFrame()class FindStudent(Frame):"""用于显示学生查询系统的查询结果"""def __init__(self, master=None):super().__init__(master)  # super()代表了父类的定义self.master = masterself.place(relx=0.1, relwidth=0.8, relheight=1)'''创建组件'''global Student, FindResultcolumns = Student[0]widths = [100, 60, 60, 60, 60, 60, 60, 60, 90]self.label_tit = Label(self, text='查询结果', width=12, height=1, fg='black', font=('黑体', 25))self.btn_rtn = Button(self, text='返回上一级', width=12, height=1, bg='gray', font=('黑体', 15))self.btnQuit = Button(self, text='退出系统', width=12, height=1, font=('黑体', 15), command=Exit)self.canvas = Canvas(self)  # 创建canvasself.treeview = ttk.Treeview(self.canvas, show="headings", columns=columns)  # 表格for i in range(len(widths)):self.treeview.column(columns[i], width=widths[i], anchor='center')  # 表示列,不显示self.treeview.heading(columns[i], text=columns[i])  # 显示表头self.treeview.insert('', 1, values=FindResult)self.treeview.place(relx=0, rely=0, relwidth=1, relheight=1)self.canvas.place(relx=0, rely=0.2, relwidth=1, height=200)self.label_tit.place(relx=0.25, rely=0.1, relwidth=0.5, height=40)self.btnQuit.place(relx=0.2, rely=0.6, width=150, height=40)self.btn_rtn.place(relx=0.55, rely=0.6, width=150, height=40)self.btn_rtn.bind('<Button-1>', self.btn_rtn_ev)def btn_rtn_ev(self, event):global Empty, registerFrameself.destroy()Empty = Frame(root, height=100)Empty.pack()registerFrame = RegisterFrame(master=root, TypeChoice='Student')class AdminSetFrame(Frame):"""学校信息初始化界面"""def __init__(self, master=None):super().__init__(master)  # super()代表了父类的定义self.master = masterself.pack(anchor='n')"""创建组件"""self.label_tit = Label(self, text='管理员账户设置', width=24, height=1,fg='black', font=('黑体', 25))self.label_adm = Label(self, text='请输入账号:      ', width=18, height=1,fg='black', font=('黑体', 15))self.label_rmd = Label(self, text='(可新增账号或修改已有账号密码)', width=18, height=1,fg='black', font=('黑体', 8))self.label_pwd = Label(self, text='请输入密码:      ', width=18, height=1,fg='black', font=('黑体', 15))self.label_pwdagn = Label(self, text='再次输入密码密码:', width=18, height=1,fg='black', font=('黑体', 15))self.btn_cfm = Button(self, text='确定', width=8, height=1, bg='gray', font=('黑体', 15))self.btn_rtn = Button(self, text='返回上一级', width=10, height=1, bg='gray', font=('黑体', 15))self.btn_cnc = Button(self, text='清空', width=8, height=1, bg='gray', font=('黑体', 15))self.btnQuit = Button(self, text='退出系统', width=8, height=1, font=('黑体', 15), command=Exit)self.v_adm = StringVar()self.v_pwd = StringVar()self.v_pwdagn = StringVar()self.entry_adm = Entry(self, textvariable=self.v_adm, width=24)self.entry_pwd = Entry(self, textvariable=self.v_pwd, width=24)self.entry_pwdagn = Entry(self, textvariable=self.v_pwdagn, width=24)self.label_tit.grid(row=0, column=0, columnspan=24, pady=30)self.label_adm.grid(row=1, column=0, columnspan=12)self.label_rmd.place(x=110, rely=0.2, width=200, height=20)self.label_pwd.grid(row=2, column=0, columnspan=12)self.label_pwdagn.grid(row=3, column=0, columnspan=12)self.btn_cfm.grid(row=5, column=0, pady=20, padx=20, columnspan=8)self.btn_cnc.grid(row=5, column=10, pady=20, padx=20, columnspan=8)self.btn_rtn.grid(row=5, column=20, pady=20, padx=20, columnspan=8)self.btnQuit.grid(row=6, column=10, pady=20, columnspan=8)self.entry_adm.grid(row=1, column=15, pady=10, columnspan=24)self.entry_pwd.grid(row=2, column=15, pady=10, columnspan=24)self.entry_pwdagn.grid(row=3, column=15, pady=10, columnspan=24)self.btn_cfm.bind('<Button-1>', self.btn_cfm_ev)self.btn_cnc.bind('<Button-1>', self.btn_cnc_ev)self.btn_rtn.bind('<Button-1>', self.btn_rtn_ev)def btn_cfm_ev(self, event):global Adminadm = pwd = Save = Falseif self.v_adm.get() == '':messagebox.showinfo(title='提示信息', message='请输入账号!')else:adm = Trueif self.v_pwd.get() != self.v_pwdagn.get():messagebox.showinfo(title='提示信息', message='两次输入密码不一致!')else:pwd = Trueif adm and pwd:for x in range(len(Admin)):if self.v_adm.get() == Admin[x][0]:Save = xif Save == 0 and messagebox.askokcancel(title='提示消息', message='该账号已存在,是否修改密码?'):Admin.append(['admin', self.v_pwd.get()])elif not Save and messagebox.askokcancel(title='提示消息', message='是否新建账号?'):Admin.append([self.v_adm.get(), self.v_pwd.get()])elif messagebox.askokcancel(title='提示消息', message='该账号已存在,是否修改密码?'):Admin[Save] = [self.v_adm.get(), self.v_pwd.get()]def btn_cnc_ev(self, event):self.v_adm.set('')self.v_pwd.set('')self.v_pwdagn.set('')def btn_rtn_ev(self, event):global root, Empty, adMenuFrame, showFrameself.destroy()Empty.destroy()adMenuFrame = AdMenuFrame(master=root)showFrame = ShowFrame(master=root)def Windows(width, height, app='FirstFrame(master=root)', empty=True):global root, Student, Empty, Schoolx = root.winfo_screenwidth()y = root.winfo_screenheight()align_str = '%dx%d+%d+%d' % (width, height, (x - width) / 2, (y - height) / 2)root.geometry(align_str)if Dp.Student.School is None:root.title('学生成绩系统')else:root.title('学生成绩系统 BY {0}'.format(Dp.Student.School))if empty:Empty = Frame(root, height=100)Empty.pack()eval(app)get_time()root.protocol('WM_DELETE_WINDOW', Exit)root.mainloop()def Save():if Dp.FileProcess('Save', Students=Student) and Dp.AdScProcess('Save', Admins=Admin, Schools=School):messagebox.showinfo(title='提示消息', message='数据保存成功,欢迎下次使用!')def Exit():# True or 'False'res = messagebox.askokcancel(title='提示消息', message='是否退出系统?')if res:Save()root.destroy()def get_time():  # 屏幕刷新时间global root, TimeNowtime_str = time.strftime("%H:%M:%S", time.localtime())  # 获得系统现在时间TimeNow = Label(root, text=time_str, width=12, height=1, fg='black', font=('黑体', 25))TimeNow.place(relx=0.7, rely=0.9)time_str = time.strftime("%H:%M:%S", time.localtime())  # 获得系统现在时间TimeNow.configure(text=time_str)  # 重新设置文本标签root.after(1000, get_time)if __name__ == "__main__":'''当在该界面运行时的操作'''root = Tk()Student = Dp.FileProcess('Read')Admin, School = Dp.AdScProcess('Read')Windows(800, 600)

3.文件保存模块

  • DataProcess是一个自定义数据保存模块
  • 需要创建一个名为DataProcess.py的文件
# _*_ coding:utf-8 _*_
"""
@ name: DataProcess.py
@ 功能: 本模块用于储存学生成绩系统有关的函数
@ author : 王子潇
@ create : 2020/7
"""import csv
import os
import pickleclass Student:"""定义一个学生信息类,用于存储学生信息"""School = GPA_c_grade = GPA_m_grade = GPA_e_grade = None  # 类属性,用于存储学校的姓名及学分设置def __init__(self, num, name, sex, c_grade, m_grade, e_grade, total, ave, GPA):self.num = num  # 学号self.name = name  # 姓名self.sex = sex  # 性别self.c_grade = c_grade  # C语言成绩self.m_grade = m_grade  # 数学成绩self.e_grade = e_grade  # 英语成绩self.total = total  # 总分self.ave = ave  # 平均分self.GPA = GPA  # 平均绩点@classmethod  # 修饰器  方法==>属性def setting(cls, School):"""通过元组 ’School‘ 对 ’Student‘ 类的类属性的初始化"""cls.School = School.get('name')cls.GPA_c_grade = float(School.get('C_grade'))cls.GPA_m_grade = float(School.get('M_grade'))cls.GPA_e_grade = float(School.get('E_grade'))@classmethoddef append(cls, AppendSet):"""通过一个包含六个数据的列表 ’AppendSet‘ 新增一个Students实例对象的方法,返回值为一个Students实例对象"""num = AppendSet[0]name = AppendSet[1]sex = AppendSet[2]c_grade = round(float(AppendSet[3]), 2)  # 使 c_grade 中的值保留两位小数m_grade = round(float(AppendSet[4]), 2)e_grade = round(float(AppendSet[5]), 2)total = c_grade + m_grade + e_gradeave = total / 3ave = round(ave, 2)a = G_grade(c_grade) * Student.GPA_c_grade + G_grade(m_grade) * Student.GPA_m_grade + G_grade(e_grade) * Student.GPA_e_gradeb = Student.GPA_c_grade + Student.GPA_m_grade + Student.GPA_e_gradeGPA = round(a / b, 2)  # 使GPA中的值保留两位小数a = Student(num, name, sex, c_grade, m_grade, e_grade, total, ave, GPA)return list([a.num, a.name, a.sex, a.c_grade, a.m_grade, a.e_grade, a.total, a.ave, a.GPA])def G_grade(grade):"""用于将百分制成绩转换为5分制GPA"""if grade >= 90.0:return 5elif grade >= 85:return 4.5elif grade >= 80:return 4.0elif grade >= 75:return 3.5elif grade >= 70:return 3.0elif grade >= 65:return 2.5elif grade >= 60:return 2.0else:return 0def FileProcess(Kind, Students=None):"""用于读取或保存学生信息的csv文件 kind取值为 Read or Save"""address = os.getcwd()  # 获取当前的工作目录if not os.path.exists('学生成绩系统数据'):os.mkdir('学生成绩系统数据')  # 如果工作目录不存在’学生成绩系统数据‘子目录,则创建目录address = os.path.join(address, '学生成绩系统数据')if Kind == 'Read':try:with open('{0}/Student.csv'.format(address), 'r'):pass  # 尝试以’r‘类型打开文件,报错则说明文件不存在,则创建文件并进行初始化except FileNotFoundError:with open('{0}/Student.csv'.format(address), 'w+') as f:Stu_csv = csv.writer(f)  # 将文件的标题写入文件中Stu_csv.writerow(["学号", "姓名", "性别", "C语言", "数学", "英语", "总分", "平均分", "加权平均绩点"])finally:with open('{0}/Student.csv'.format(address), 'r') as f:Students = list(csv.reader(f))  # 将文件中的信息读取到一个二维列表中,一个元素为一个学生的信息StudentNew = []for i in range(len(Students)):if Students[i]:StudentNew.append(Students[i])  # 删除所读取文件元素中的空元素,并返回一个新列表return StudentNewelif Kind == 'Save':with open('{0}/Student.csv'.format(address), 'w+') as f:Stu_csv = csv.writer(f)  # 在进行保存时,已进行过’Read‘操作,无需判断文件是否存在Stu_csv.writerows(Students)return Trueelse:print('函数调用传参错误!')  # 当调用函数时未进行’kind‘的赋值或赋值错误则在控制台打印def AdScProcess(Kind, Admins=None, Schools=None):"""用于读取或保存系统账号以及学校信息"""address = os.getcwd()  # 获取当前工作目录if not os.path.exists('学生成绩系统数据'):  # 判断工作目录下是否存在子目录,无则创建os.mkdir('学生成绩系统数据')address = os.path.join(address, '学生成绩系统数据')if Kind == 'Read':try:with open('{0}/Admin.bat'.format(address), 'rb+'):  # 若文件不存在则创建新文件并存入基本信息passexcept FileNotFoundError:with open('{0}/Admin.bat'.format(address), 'wb+') as f:Admins = [['admin', 'admin']]Schools = {'name': None, 'C_grade': None, 'M_grade': None, 'E_grade': None}pickle.dump(Admins, f)pickle.dump(Schools, f)  # 将数据依次存入新文件finally:with open('{0}/Admin.bat'.format(address), 'rb+') as f:Admins = pickle.load(f)  # 从文件中以此取出数据并存入内存(取出顺序必须与存入顺序相同)Schools = pickle.load(f)if Schools.get('name') is not None:Student.setting(Schools)  # 当元组’Schools‘的值不为空时,对’Student‘类进行类属性的初始化return Admins, Schoolselif Kind == 'Save':with open('{0}/Admin.bat'.format(address), 'wb+') as f:pickle.dump(Admins, f)pickle.dump(Schools, f)  # 将数据依次存入文件return Trueelse:print('函数调用传参错误!')  # 当kind的值不为Read or Save 时,在控制台报错

Python 基于tkinter模块的GUI可视化学生成绩管理系统实现(含文件保存)相关推荐

  1. 基于GUI的学生成绩管理系统

    基于GUI的学生成绩管理系统 一.项目背景 二.项目要求 三.前期准备 1.软硬件平台 2. MySQL驱动 四.核心类介绍 1.Student类 2.UserInterface类 2.1.变量定义 ...

  2. 基于Servlet+jsp+mysql开发javaWeb学生成绩管理系统

    你知道的越多,你不知道的越多 点赞再看,养成习惯 如果您有疑问或者见解,或者没有积分想获取项目,欢迎指教: 企鹅:869192208 文章目录 一.开发背景 二. 需求分析 三.开发环境 四.运行效果 ...

  3. 【数据分析】基于matlab GUI学生成绩管理系统【含Matlab源码 1981期】

    ⛄一.案例简介(仅供参考) 1 设计目标 1.1 设计一个基于GUI的学生成绩管理与分析系统 (1)设计一个插入背景的登录界面 (2)以某班某课成绩为研究对象,设计几个对话框,实现: 1.2 查询功能 ...

  4. 基于jsp+mysql+java+ssm高校学生成绩管理系统——计算机毕业设计

    项目介绍 学生成绩管理作为一所高校对学生评价的一个标杆,它直接的体现了学生在校学习的成果.由于近年来很多学校都在扩大规模,在校学生数量甚至破万,倘若单一的采用人工记录成绩的方法明显已经显得力不从心,因 ...

  5. 按照学号查找学生_[源码和文档分享]基于JAVA和MYSQL数据库的学生成绩管理系统...

    一.需求分析 本系统是学生成绩管理系统,所以应该做到可以录入学生成绩,修改学生成绩,删除学生成绩,查询学生成绩,以及最后的所有学生按照GPA排名. 本系统的数据来源期末考试成绩,用来实现录入,查询,修 ...

  6. java编程实现学生成绩管理系统_java 用文件实现的学生成绩管理系统

    [实例简介] yu华南理工大学网络学院2014秋季 "计算机操作系统"课程设计大作业 一.题目: 用文件实现的学生成绩管理系统 二.目的 学生通过本次实验编程实现一个班级学生成绩的 ...

  7. 基于python 使用tk模块和mysql实现学生信息管理系统

    学生信息管理系统 好久没有发文啦,经过一段时间的学习,有所收获,写了个小项目,记录一下学习过程.好啦,废话不多说,我们直接说实现,看效果. 首先系统是有三个视图,一个管理员,一个教师,一个学生,运行效 ...

  8. 基于PHP和mysql的简单学生成绩管理系统

    本系统主要架构图如上图所示.PS:register_check.php的自动注册代码写在check.php里了. 使用数据库的两张表,user_info用户信息表和stu_info学生成绩信息表. 提 ...

  9. php与MYSQL制作学生成绩系统,基于PHP和mysql的简单学生成绩管理系统

    本系统主要架构图如上图所示.PS:register_check.php的自动注册代码写在check.php里了. 使用数据库的两张表,user_info用户信息表和stu_info学生成绩信息表. 提 ...

最新文章

  1. 用python画皮卡丘画法-python turtle绘图库绘制【皮卡丘】源码
  2. 《C程序设计语言》读书笔记----习题1-21
  3. 设计模式--适配器(Adapter)模式
  4. Java容器的遍历之增强for循环
  5. FRIDA 实用手册
  6. Web前后端笔记-vue封装http请求添加signature及后端(Java)解析并验证
  7. 血淋淋的教训—将Vue项目打包成app的跨域问题
  8. Oracle绑定变量分级(Bind Graduation)
  9. python实现常见的整数进制、字符进制、ASCII码进制之间的转换
  10. Linux音频驱动-AOSC之Codec
  11. 关于在用Swift开发iOS时如何隐藏NavigationBar和TabBar
  12. Eclipse官方汉化Zip包下载地址及安装方式
  13. 2021年数学建模B组代码
  14. 腾讯云学生机介绍—校园扶持计划
  15. vue结合echarts开发柱状图+折线图合并的图表
  16. 【Unity】出现NullReferenceException:Object reference not set to an instance of an object.的原因总结
  17. HTML和Css基础知识点笔记
  18. node+ npm + yarn 安装及上手
  19. C++ 求最大公因数
  20. 信息奥赛一本通1225:金银岛

热门文章

  1. android 自定义view 动画效果,Android自定义view实现阻尼效果的加载动画
  2. 按键精灵手机版 代码收藏
  3. 各国家 MCC 和 MNC 列表3
  4. 2022-01-18 Caffe+Window11+Visual Studio 2015+Python3.5 CPU+GPU 配置详细教程
  5. Ubuntu-18.04 安装 ROS 系统
  6. React项目的打包与部署到腾讯云
  7. 好名字——能看出方法特征的名字才是好名字
  8. vue2.0专题:通信
  9. UnityHub 无需登录 傻瓜教程 一键搞定
  10. Stanford iOS7 Lecture 1-3 demo