通过python图形化界面和数据库实现学生成绩管理系统
实现功能大概如下:
from database import *
from win import *
class Login:
def __init__(self):
"""创建登录界面"""
self.db = Database()
# 创建主窗口,用于容纳其它组件
self.login_root = Tk()
# 给主窗口设置标题内容
self.login_root.title("登录系统")
# 设置窗口大小和位置
screenwidth = self.login_root.winfo_screenwidth()
screenheight = self.login_root.winfo_screenheight()
width = 500
high = 300
self.login_root.geometry('%dx%d+%d+%d' % (width, high, (screenwidth - width) / 2, (screenheight - high) / 2))
# 创建画布
self.canvas = Canvas(self.login_root, height=400, width=700)
self.image_file = PhotoImage(file="123.gif")
# 加载图片文件,并将图片置于画布上
self.image = self.canvas.create_image(0, 0, anchor='nw', image=self.image_file)
# 放置画布(为上端)
self.canvas.pack(side='top')
# 创建账户标签
Label(self.login_root, text='账户').place(x=90, y=70)
# 创建密码标签
Label(self.login_root, text='密码').place(x=90, y=95)
account = StringVar()
password = StringVar()
# 创建一个账号输入框,并设置尺寸
Entry(self.login_root, width=30, textvariable=account).place(x=140, y=70)
# 创建一个密码输入框,并设置尺寸
Entry(self.login_root, show='*', width=30, textvariable=password).place(x=140, y=95)
# 创建一个登录系统的按钮
Button(self.login_root, command=lambda: self.login(account, password), text="登录", width=10).place(x=155, y=120)
# 创建一个注册系统的按钮
Button(self.login_root, command=lambda: self.register(account, password), text="注册", width=10).place(x=250, y=120)
mainloop()
def login(self, account, password):
"""登录功能实现"""
account = account.get()
password = password.get()
if account.strip() and password.strip():
if self.db.prepare(f"select * from stu_user where stu_account='{account}' and stu_password='{password}'"):
showinfo("提示", "登录成功")
self.login_root.destroy()
Win()
else:
showerror("错误", "密码或账号错误请重新输入")
else:
showerror("错误", "账号信息没有输入完整")
def register(self, account, password):
"""注册功能实现"""
account = account.get()
password = password.get()
# 判断信息是否输入完整
if account.strip() and password.strip():
if self.db.prepare(f"select * from stu_user where stu_account='{account}'") == 0:
self.db.prepare(f"insert into stu_user values ('{account}', '{password}')")
showinfo("提示", "注册成功")
else:
showerror("错误", "该账号已被注册")
else:
showerror("错误", "请输入完整的账号信息")
import MySQLdb
class Database(object):
def __init__(self):
"""连接数据库"""
self.db = MySQLdb.connect("localhost", "root", "1535258", "manage", charset='utf8')
self.cursor = self.db.cursor()
def prepare(self, sql):
"""执行sql语句"""
return self.cursor.execute(sql)
def update(self):
"""提交到数据库执行"""
self.db.commit()
def close(self):
"""关闭数据库"""
self.db.close()
from tkinter import *
from tkinter import ttk
from tkinter.messagebox import *
from show_info import ShowInfo
from modify_info import ModifyInfo
from search_info import SearchInfo
from del_info import DelInfo
from statistics_info import StatisticsInfo
from add_info import AddInfo
from sort import TreeviewSortColumn
from section_query import SectionQuery
class Win(object):
def __init__(self):
"""主界面基本设置"""
# 创建窗口
root = Tk()
# 设置窗口大小和并将位置设置到屏幕中央
screenwidth = root.winfo_screenwidth()
screenheight = root.winfo_screenheight()
width = 700
high = 600
root.geometry('%dx%d+%d+%d' % (width, high, (screenwidth - width) / 2, (screenheight - high) / 2))
root.title('学生管理系统')
# 设置各个文本框的标签,并固定位置
Label(root, text="学号:").place(relx=0, rely=0.05, relwidth=0.1)
Label(root, text="姓名:").place(relx=0.5, rely=0.05, relwidth=0.1)
Label(root, text="Python:").place(relx=0, rely=0.1, relwidth=0.1)
Label(root, text="C语言:").place(relx=0.5, rely=0.1, relwidth=0.1)
# 设置各个文本框内容所对应的变量
self.stu_id = StringVar()
self.stu_name = StringVar()
self.stu_python = StringVar()
self.stu_c = StringVar()
# 设置各个文本框并固定位置
Entry(root, textvariable=self.stu_id).place(relx=0.1, rely=0.05, relwidth=0.35, height=25)
Entry(root, textvariable=self.stu_name).place(relx=0.6, rely=0.05, relwidth=0.35, height=25)
Entry(root, textvariable=self.stu_python).place(relx=0.1, rely=0.1, relwidth=0.35, height=25)
Entry(root, textvariable=self.stu_c).place(relx=0.6, rely=0.1, relwidth=0.35, height=25)
# 设置窗口的标题标签
Label(root, text='学生信息管理', bg='white', fg='red', font=('宋体', 15)).pack(side=TOP, fill='x')
# 创建表格并设置相关属性
self.tree_view = ttk.Treeview(root, show='headings', column=('stu_id', 'stu_name', 'stu_python', 'stu_c'))
sb = Scrollbar(root, orient='vertical', command=self.tree_view.yview)
sb.place(relx=0.971, rely=0.028, relwidth=0.024, relheight=0.958)
# 设置每列的属性
self.tree_view.configure(yscrollcommand=sb.set)
self.tree_view.column('stu_id', width=150, anchor="center")
self.tree_view.column('stu_name', width=150, anchor="center")
self.tree_view.column('stu_python', width=150, anchor="center")
self.tree_view.column('stu_c', width=150, anchor="center")
# 设置每行的属性
self.tree_view.heading('stu_id', text='学号', command=lambda: TreeviewSortColumn().table_sort(self.tree_view, 'stu_id', False))
self.tree_view.heading('stu_name', text='姓名', command=lambda: TreeviewSortColumn().table_sort(self.tree_view, 'stu_name', False))
self.tree_view.heading('stu_python', text='Python', command=lambda: TreeviewSortColumn().table_sort(self.tree_view, 'stu_python', False))
self.tree_view.heading('stu_c', text='C语言', command=lambda: TreeviewSortColumn().table_sort(self.tree_view, 'stu_c', False))
# 设置表格位置
self.tree_view.place(relx=0.02, rely=0.3, relwidth=0.96)
# 设置按钮,并固定位置
Button(root, text="显示所有信息", command=lambda: ShowInfo(self.tree_view)).place(relx=0.05, rely=0.2, width=80)
Button(root, text="添加学生信息", command=lambda: AddInfo(self.stu_id, self.stu_name, self.stu_python, self.stu_c)).place(relx=0.20, rely=0.2, width=80)
Button(root, text="删除学生信息", command=lambda: DelInfo(self.stu_id, self.stu_name, self.stu_python, self.stu_c)).place(relx=0.35, rely=0.2, width=80)
Button(root, text="修改学生信息", command=lambda: ModifyInfo(self.stu_id, self.stu_name, self.stu_python, self.stu_c)).place(relx=0.50, rely=0.2, width=80)
Button(root, text="统计学生信息", command=lambda: StatisticsInfo()).place(relx=0.65, rely=0.2, width=80)
Button(root, text="查询学生信息", command=lambda: SearchInfo(self.stu_id, self.stu_name, self.stu_python, self.stu_c, self.tree_view)).place(relx=0.80, rely=0.2, width=80)
# 创建一个顶级菜单
menubar = Menu(root)
# 创建下拉菜单,然后将它添加到顶级菜单中
filemenu = Menu(menubar, tearoff=False)
section_menu = Menu(filemenu, tearoff=False)
python_menu = Menu(section_menu, tearoff=False)
c_menu = Menu(section_menu, tearoff=False)
total_menu = Menu(filemenu, tearoff=False)
# 设置下拉菜单的label
menubar.add_cascade(label="选项", menu=filemenu)
filemenu.add_cascade(label="分段筛选数据", menu=section_menu)
filemenu.add_cascade(label="按总成绩排序", menu=total_menu)
filemenu.add_separator()
filemenu.add_command(label="退出", command=lambda: self.callback(root))
section_menu.add_cascade(label="Python", menu=python_menu)
section_menu.add_cascade(label="C语言", menu=c_menu)
section_menu.add_command(label="自定义区间", command=lambda: SectionQuery(self.tree_view).custom(self.tree_view))
python_menu.add_command(label="0-60", command=lambda: SectionQuery(self.tree_view).section(self.tree_view, 'python', 0, 60))
python_menu.add_command(label="60-80", command=lambda: SectionQuery(self.tree_view).section(self.tree_view, 'python', 60, 80))
python_menu.add_command(label="80-100", command=lambda: SectionQuery(self.tree_view).section(self.tree_view, 'python', 80, 100))
c_menu.add_command(label="0-60", command=lambda: SectionQuery(self.tree_view).section(self.tree_view, 'c', 0, 60))
c_menu.add_command(label="60-80", command=lambda: SectionQuery(self.tree_view).section(self.tree_view, 'c', 60, 80))
c_menu.add_command(label="80-100", command=lambda: SectionQuery(self.tree_view).section(self.tree_view, 'c', 80, 100))
total_menu.add_command(label="升序", command=lambda: TreeviewSortColumn().total_sort(self.tree_view))
total_menu.add_command(label="降序", command=lambda: TreeviewSortColumn().total_sort(self.tree_view, "desc"))
# 显示菜单
root.config(menu=menubar)
# 绑定单击离开事件
self.tree_view.bind('' , self.tree_view_click)
# 捕获关闭按钮
root.protocol("WM_DELETE_WINDOW", lambda: self.callback(root))
# 事件循环
root.mainloop()
def tree_view_click(self, event):
"""点击表格中的一项数据后将其显示在相应文本框上"""
for item in self.tree_view.selection():
item_text = self.tree_view.item(item, "values")
self.stu_id.set(item_text[0])
self.stu_name.set(item_text[1])
self.stu_python.set(item_text[2])
self.stu_c.set(item_text[3])
def callback(self, root):
"""退出时的询问"""
if askokcancel("询问", "是否关闭该窗口?"):
root.destroy()
from database import Database
from tkinter.messagebox import *
class AddInfo(object):
def __init__(self, stu_id, stu_name, stu_python, stu_c):
"""添加学生信息"""
db = Database()
stu_id = stu_id.get()
stu_name = stu_name.get()
try:
if not(stu_id.strip() and stu_name.strip()):
raise ValueError
stu_python = int(stu_python.get())
stu_c = int(stu_c.get())
if 0 <= stu_python <= 100 and 0 <= stu_c <= 100:
if db.prepare(f"select * from student where stu_id='{stu_id}'") == 0:
sql = f"insert into student values('{stu_id}', '{stu_name}', {stu_python}, {stu_c})"
db.prepare(sql)
db.update()
showinfo("提示", "添加成功")
else:
showerror("添加失败", "该学号重复")
else:
showerror("添加失败", "各科分数应在0-100之间")
except ValueError:
showerror("添加失败", "信息未填写完整或者成绩输入为非数字")
from database import Database
from tkinter.messagebox import *
class SearchInfo(object):
def __init__(self, stu_id, stu_name, stu_python, stu_c, tree_view):
"""模糊查询"""
db = Database()
x = tree_view.get_children()
for item in x:
tree_view.delete(item)
stu_name = stu_name.get()
stu_id = stu_id.get()
stu_python = stu_python.get()
stu_c = stu_c.get()
try:
if stu_python != '':
stu_python = int(stu_python)
else:
stu_python = 0
if stu_c != '':
stu_c = int(stu_c)
else:
stu_c = 0
# 该sql语句筛选出你模糊查询的各种数据(可以组合)
sql = f'''select * from student where (stu_id like '%{stu_id}%' or if(not stu_id, NULL, '') = '{stu_id}')
and (stu_name like '%{stu_name}%' or if(not stu_name, '', NULL)='{stu_name}') and
(if(not python, NULL, 0)={stu_python} or cast(python as char) like '%{stu_python}%') and
(if(not c, NULL, 0)={stu_c} or cast(c as char) like '%{stu_c}%')'''
# 只有文本框内有有效数据时才执行该语句
if (stu_id or stu_name or stu_python or stu_c) and db.prepare(sql):
db.update()
showinfo("提示", "已完成查询")
student_tuple = db.cursor.fetchall()
for item in student_tuple:
tree_view.insert('', 'end', values=item)
else:
showerror("查询失败", "未查询到该学生信息")
except ValueError:
showerror("查询失败", "成绩只能为数字")
db.close()
from database import Database
class ShowInfo(object):
def __init__(self, tree_view):
"""将所有学生信息显示在表格上"""
db = Database()
x = tree_view.get_children()
for item in x:
tree_view.delete(item)
db.cursor.execute("select * from student")
student_tuple = db.cursor.fetchall()
for item in student_tuple:
tree_view.insert("", 'end', values=item)
from database import Database
from tkinter.messagebox import *
class DelInfo(object):
def __init__(self, stu_id, stu_name, stu_python, stu_c):
"""模糊删除"""
db = Database()
stu_id = stu_id.get()
stu_name = stu_name.get()
stu_python = stu_python.get()
stu_c = stu_c.get()
try:
if stu_python != '':
stu_python = int(stu_python)
else:
stu_python = 0
if stu_c != '':
stu_c = int(stu_c)
else:
stu_c = 0
sql = f'''select * from student where (stu_id like '%{stu_id}%' or if(not stu_id, NULL, '') = '{stu_id}')
and (stu_name like '%{stu_name}%' or if(not stu_name, '', NULL)='{stu_name}') and
(if(not python, NULL, 0)={stu_python} or cast(python as char) like '%{stu_python}%')
and (if(not c, NULL, 0)={stu_c} or cast(c as char) like '%{stu_c}%')'''
if (stu_id or stu_name or stu_python or stu_c) and db.prepare(sql):
db.update()
stu_tuple = db.cursor.fetchall()
for i in range(len(stu_tuple)):
if askokcancel("提示", f"是否删除该学生的信息(学号:{stu_tuple[i][0]} 姓名:{stu_tuple[i][1]} Python:{stu_tuple[i][2]} C语言:{stu_tuple[i][3]})"):
db.prepare(f"delete from student where (stu_id like '%{stu_id}%' or if(not stu_id, NULL, '') = '{stu_id}') and (stu_name like '%{stu_name}%' or if(not stu_name, '', NULL)='{stu_name}') and (if(not python, NULL, 0)={stu_python} or cast(python as char) like '%{stu_python}%') and (if(not c, NULL, 0)={stu_c} or cast(c as char) like '%{stu_c}%') limit 1")
db.update()
showinfo("提示", "删除成功")
else:
showerror("删除失败", "未查询到该学生信息")
except ValueError:
showerror("删除失败", "成绩只能为数字")
from database import Database
from tkinter.messagebox import *
class ModifyInfo(object):
def __init__(self, stu_id, stu_name, stu_python, stu_c):
"""修改学生信息"""
db = Database()
stu_id = stu_id.get()
stu_name = stu_name.get()
try:
if not (stu_id.strip() and stu_name.strip()):
raise ValueError
stu_c = int(stu_c.get())
stu_python = int(stu_python.get())
if 0 <= stu_python <= 100 and 0 <= stu_c <= 100:
if db.prepare(f"select * from student where stu_id={stu_id}") != 0:
db.prepare(f"update student set stu_name='{stu_name}', python={stu_python},"
f" c={stu_c} where stu_id='{stu_id}'")
db.update()
showinfo("提示", "修改成功")
else:
showerror("修改失败", "未查询到该同学信息")
else:
showerror("修改失败", "各科分数应在0-100之间")
except ValueError:
showerror("修改失败", "信息未填写完整或者成绩输入为非数字")
db.close()
from tkinter import *
from database import *
from tkinter.messagebox import *
class SectionQuery(object):
def __init__(self, tree_view):
"""清空表格中显示的内容"""
self.db = Database()
x = tree_view.get_children()
for item in x:
tree_view.delete(item)
def section(self, tree_view, *args):
"""快捷版分段显示"""
self.db.prepare(f"select * from student where {args[0]}>{args[1]} and {args[0]}<{args[2]}")
self.insert(tree_view)
showinfo("提示", f"已筛选出{args[0]}成绩从{args[1]}—{args[2]}的学生的信息")
def custom(self, tree_view):
"""自定义版分段显示"""
# 创建自定义分段窗口
top = Toplevel()
# 使窗口位于屏幕中央
screenwidth = top.winfo_screenwidth()
screenheight = top.winfo_screenheight()
width = 500
high = 200
top.geometry('%dx%d+%d+%d' % (width, high, (screenwidth - width) / 2, (screenheight - high) / 2))
Label(top, text="Python").place(relx=0.48, rely=0, relwidth=0.1)
Label(top, text="————").place(relx=0.48, rely=0.2, relwidth=0.1)
Label(top, text="C语言").place(relx=0.48, rely=0.4, relwidth=0.1)
Label(top, text="————").place(relx=0.48, rely=0.6, relwidth=0.1)
python_limit1 = StringVar()
python_limit2 = StringVar()
c_limit1 = StringVar()
c_limit2 = StringVar()
Entry(top, textvariable=python_limit1).place(relx=0.1, rely=0.2, relwidth=0.35, height=25)
Entry(top, textvariable=python_limit2).place(relx=0.6, rely=0.2, relwidth=0.35, height=25)
Entry(top, textvariable=c_limit1).place(relx=0.1, rely=0.6, relwidth=0.35, height=25)
Entry(top, textvariable=c_limit2).place(relx=0.6, rely=0.6, relwidth=0.35, height=25)
mb = Menubutton(top, text="筛选", relief=RAISED)
mb.place(relx=0.5, rely=0.8)
filemenu = Menu(mb, tearoff=False)
filemenu.add_command(label="按Python分段", command=lambda: self.section_python(python_limit1, python_limit2, tree_view))
filemenu.add_command(label="按C语言分段", command=lambda: self.section_c(c_limit1, c_limit2, tree_view))
filemenu.add_separator()
filemenu.add_command(label="按Python和C语言分段", command=lambda: self.section_all(python_limit1, python_limit2, c_limit1, c_limit2, tree_view))
mb.config(menu=filemenu)
def check_data(self, limit1, limit2):
"""检查输入的数据是否合格"""
try:
limit1 = int(limit1.get())
limit2 = int(limit2.get())
if limit1 > limit2:
up = limit1
down = limit2
else:
up = limit2
down = limit1
return up, down
except ValueError:
showerror("分段筛选失败", "分段区间未填写完整或输入为非数字")
def section_python(self, python_limit1, python_limit2, tree_view):
"""按python成绩分段筛选"""
# 由与已有方法对异常进行了处理所以此处出现异常直接pass
try:
python_up, python_down = self.check_data(python_limit1, python_limit2)
if self.db.prepare(f"select * from student where python>{python_down} and python<{python_up}") != 0:
self.insert(tree_view)
showinfo("提示", f"已筛选出Python成绩从{python_down}—{python_up}的学生的信息")
else:
showinfo("提示", f"没有Python成绩从{python_down}—{python_up}的学生的信息")
except TypeError:
pass
self.db.close()
def section_c(self, c_limit1, c_limit2, tree_view):
"""按照C语言成绩分段筛选"""
try:
c_up, c_down = self.check_data(c_limit1, c_limit2)
if self.db.prepare(f"select * from student where c>{c_down} and c<{c_up}") != 0:
self.insert(tree_view)
showinfo("提示", f"已筛选出C语言成绩从{c_down}—{c_up}的学生的信息")
else:
showinfo("提示", f"没有C语言成绩从{c_down}—{c_up}的学生的信息")
except TypeError:
pass
self.db.close()
def section_all(self, python_limit1, python_limit2, c_limit1, c_limit2, tree_view):
"""按照python和C语言成绩分段筛选"""
try:
c_up, c_down = self.check_data(c_limit1, c_limit2)
python_up, python_down = self.check_data(python_limit1, python_limit2)
if self.db.prepare(f"select * from student where c>{c_down} and c<{c_up} and python>{python_down} and python<{python_up}") != 0:
self.insert(tree_view)
showinfo("提示", f"已筛选出Python成绩从{python_down}—{python_up}"
f"C语言成绩从{c_down}—{c_up}的学生的信息")
else:
showinfo("提示", f"没有Python成绩从{python_down}—{python_up}"
f"C语言成绩从{c_down}—{c_up}的学生的信息")
except TypeError:
pass
self.db.close()
def insert(self, tree_view):
""""向表格中插入筛选出来的数据"""
student_tuple = self.db.cursor.fetchall()
for item in student_tuple:
tree_view.insert("", 'end', values=item)
from tkinter.messagebox import *
from database import Database
class TreeviewSortColumn(object): # Treeview、列名、排列方式
def table_sort(self, tv, col, reverse):
"""点击表头进行排序"""
# 因为排序utf-8编号问题所以汉字排序不是按首字母来的所以转化为gbk编码
if col == 'stu_python' or col == 'stu_c':
l = [(int(tv.set(k, col)), k) for k in tv.get_children('')]
else:
l = [(tv.set(k, col), k) for k in tv.get_children('')]
if col == 'stu_name':
l = [(i[0].encode('GBK'), i[1]) for i in l]
l.sort(reverse=reverse)
l = [(i[0].decode('GBK'), i[1])for i in l]
else:
l.sort(reverse=reverse) # 排序方式
# rearrange items in sorted positions
for index, (val, k) in enumerate(l): # 根据排序后索引移动
tv.move(k, '', index)
col_dict = {True: '降序', False: '升序', 'stu_id': '学号', 'stu_name': '姓名', 'stu_python': 'Python成绩', 'stu_c': 'C语言成绩'}
showinfo("提示", f"已按{col_dict[col]}{col_dict[reverse]}排序")
tv.heading(col, command=lambda: TreeviewSortColumn().table_sort(tv, col, not reverse)) # 重写标题,使之成为再点倒序的标题
def total_sort(self, tree_view, select=''):
"""对总成绩排序"""
db = Database()
db.prepare("select * from student order by c+ python " + select)
db.update()
sort_dict = {'': '升序', 'desc': '降序'}
showinfo("提示", f"已按总成绩{sort_dict[select]}排序")
x = tree_view.get_children()
for item in x:
tree_view.delete(item)
student_tuple = db.cursor.fetchall()
db.close()
for item in student_tuple:
tree_view.insert("", 'end', values=item)
from tkinter import ttk
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
from tkinter import *
from tkinter.messagebox import *
from database import Database
class StatisticsInfo(object):
def __init__(self):
"""创建显示统计的窗口"""
top = Toplevel()
self.db = Database()
screenwidth = top.winfo_screenwidth()
screenheight = top.winfo_screenheight()
width = 700
high = 600
top.geometry('%dx%d+%d+%d' % (width, high, (screenwidth - width) / 2, (screenheight - high) / 2))
# 创建显示数据的表格
self.tree_view = ttk.Treeview(top, show='headings', column=('object', 'max', 'min', 'average', 'fail',
'pass', 'middle', 'good', 'super', 'count'))
self.tree_view.column('object', width=50, anchor="center")
self.tree_view.column('max', width=50, anchor="center")
self.tree_view.column('min', width=50, anchor="center")
self.tree_view.column('average', width=50, anchor="center")
self.tree_view.column('fail', width=50, anchor="center")
self.tree_view.column('pass', width=50, anchor="center")
self.tree_view.column('middle', width=50, anchor="center")
self.tree_view.column('good', width=50, anchor="center")
self.tree_view.column('super', width=50, anchor="center")
self.tree_view.column('count', width=50, anchor="center")
self.tree_view.heading('object', text='课程')
self.tree_view.heading('max', text='最高分')
self.tree_view.heading('min', text='最低分')
self.tree_view.heading('average', text='平均分')
self.tree_view.heading('fail', text='不及格')
self.tree_view.heading('pass', text='及格')
self.tree_view.heading('middle', text='中')
self.tree_view.heading('good', text='良')
self.tree_view.heading('super', text='优')
self.tree_view.heading('count', text='总人数')
self.tree_view.place(relx=0.02, rely=0.3, relwidth=0.96)
self.statistics()
def statistics(self):
""""统计数据并显示在表格上"""
if self.db.prepare(
"select max(python), min(python), round(avg(python),1), count(python<60 or null), count(python<70 and "
"python>60 or null), count(70
"null), count(90) != 0:
student_tuple = self.db.cursor.fetchall()
student_tuple = ("Python",) + student_tuple[0]
self.tree_view.insert("", 0, values=student_tuple)
self.db.prepare("select max(c), min(c), round(avg(c),1), count(c<60 or null), count(c<70 and "
"c>60 or null), count(70
"null), count(90)
student_tuple = self.db.cursor.fetchall()
student_tuple = ("C语言",) + student_tuple[0]
self.tree_view.insert("", 1, values=student_tuple)
self.chart()
else:
showerror("统计失败", "没有学生数据无法进行统计")
def chart(self):
""""统计数据的柱状图"""
# 柱状图
# 使图形中的中文正常编码显示
mpl.rcParams["font.sans-serif"] = ["SimHei"]
# 每个柱子下标的索引
self.db.prepare("select * from student")
stu_tuple = self.db.cursor.fetchall()
self.db.close()
x = np.arange(len(stu_tuple))
y = [x[2] for x in stu_tuple]
y1 = [x[3] for x in stu_tuple]
# 柱子的宽度
bar_width = 0.35
tick_label = [x[1] for x in stu_tuple]
# 绘制柱状图并设置其各项属性
plt.bar(x, y, bar_width, align="center", color="c", label="Python", alpha=0.5)
plt.bar(x + bar_width, y1, bar_width, color="b", align="center", label="C语言", alpha=0.5)
plt.tight_layout(pad=0.4, w_pad=10.0, h_pad=3.0)
plt.title('学生成绩统计表')
plt.xlabel("姓名")
plt.ylabel("成绩")
plt.xticks(x + bar_width / 2, tick_label)
plt.xticks(rotation=-90)
plt.yticks(np.arange(0, 101, 20))
# 添加图例
plt.legend(loc="upper left")
plt.show()
from login import Login
if __name__ == '__main__':
Login()