学生成绩管理系统-Python tkinter图形化界面+mysql+柱状图

通过python图形化界面和数据库实现学生成绩管理系统

实现功能大概如下:

  1. 基本功能增删改查
  2. 限制成绩在各种情况下只能为0-100
  3. 实现成绩的统计功能(柱状图显示)
  4. 筛选各个成绩区间的学生信息
  5. 实现排序功能
  6. 登录注册功能
  7. 对各种错误进行捕获

项目部分效果展示

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

登录注册模块代码

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('<ButtonRelease-1>', 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<python and python<80 or null), count(80<python and python<90 or "
                "null), count(90<python or null), count(*) from student") != 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<c and c<80 or null), count(80<c and c<90 or "
                            "null), count(90<c or null), count(*) from student")
            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()

欢迎关注「IT码怪」微信公众号 ,在微信后台回复「学生成绩管理系统」,获取学生成绩管理系统源码。
在这里插入图片描述

  • 90
    点赞
  • 697
    收藏
    觉得还不错? 一键收藏
  • 28
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值