基于Tkinter开发学生成绩管理系统,能够实现增删改查操作和学生成绩统计以及生成排名报表

基于Tkinter开发学生成绩管理系统,能够实现增删改查操作和学生成绩统计以及生成排名报表

功能:增删改查,成绩排名,生成报表

db文件(MySQL连接)

class pydb:
    def datadb(self, dsql):
        # 建立数据库连接
        global db
        try:
            db = pymysql.connect(host="localhost", user="root", password="ZZXQJL@0916.com", database="mybatis",charset="utf8")
            print("数据库连接成功")
        except pymysql.Error as e:
            print("数据库连接失败:" + str(e))
        # cursor() — 数据库连接操作 python:https://www.cnblogs.com/qixu/p/6133429.html
        # 使用cursor()方法获取操作游标
        cursor = db.cursor()
        self.sql = dsql
        # 执行数据库操作
        # 使用execute方法执行SQL语句
        cursor.execute(self.sql)
        # 使用 fetchone() 方法获取一条数据
        data = cursor.fetchall()
        # 提交事务
        db.commit()
        # 关闭数据库连接
        db.close()
        # 返回数据
        return data

controller文件(功能实现)

import db
class controller:
    global dat  # 创建全局dat
    dat = db.pydb()  # 创建数据库对象
    def cha(self, id):  # 对学号进行模糊查询
        self.id = id
        sql = "select * from student where id like '%" + self.id + "%'"
        x = list(dat.datadb(sql))  # 获取数据 将数据由元组改为列表
        for i in range(len(x)):  # 将每一层数据更改成列表
            x[i] = list(x[i])
            n = x[i][3] + x[i][4] + x[i][5]  # 计算总成绩
            x[i].append(n)
        return x
    def pai(self):  # 对成绩排名
        sql = "select * from student"
        x = list(dat.datadb(sql))  # 获取数据 将数据由元组改为列表
        for i in range(len(x)):  # 将每一层数据更改成列表
            x[i] = list(x[i])
            n = x[i][3] + x[i][4] + x[i][5]  # 计算总成绩
            x[i].append(n)
        for i in range(1, len(x)):
            # 从第二个元素开始,每次取出一个元素,插入前面的序列使其有序
            for j in range(i, 0, -1):  # 插入排序
                if x[j][6] > x[j - 1][6]:
                    x[j], x[j - 1] = x[j - 1], x[j]
        return x
    def biao(self):
        x = self.pai()  # 调用排序表
        for i in range(len(x)):  # 将数据全部转为str
            for j in range(7):
                x[i][j] = str(x[i][j])
        t = [["学号", "姓名", "性别", "数学", "英语", "语文", "排名"]] + x  # 给index的列表设置表名
        f = open("student.csv", "w")
        for i in range(len(t)):  # 自动换行输出
            for j in range(7):
                f.write(t[i][j] + ',')
            f.write('\n')
        print("完成")
        f.close()
    def zeng(self, s):
        self.s = s
        # try:
        sql = "insert into student values(%d,'%s','%s',%d,%d,%d)" % (
            self.s[0], self.s[1], self.s[2], self.s[3], self.s[4], self.s[5])
        dat.datadb(sql)  # 插入数据
    def geng(self, s):
        self.s = s
        sql = "update student set name ='" + self.s[1] + "',sex='" + self.s[2] + "',math=" + self.s[3] + ",chinese=" + \
              self.s[4] + ",english=" + self.s[5] + " where id =" + self.s[0]
        dat.datadb(sql)  # 更新数据
    def shan(self, n):
        self.n = n
        sql = "delete from student where id=" + self.n
        dat.datadb(sql)  # 删除数据

index文件(系统界面)

import tkinter.ttk as tk
import csv
from tkinter import *
from controller import controller
root = Tk()  # 通过Tk的无参构造函数创建应用程序主窗口
root.title("作者:简书:每天起床都想摆")  # 设置左上角的窗口标题
root.geometry('1000x550')  # 使用geometry自定义设置窗口尺寸
root.resizable(width=False, height=False)  # 设置窗口为不可更改 固定窗口
# tkinter默认支持的是gif
photo = PhotoImage(file="img.gif")
#图片应用设置应用
Label(root,image=photo).pack()
# Tkinter标签控件(Label)用法:https://www.runoob.com/python/python-tk-label.html
# 用法:w = Label ( master, option, ... )
# master: 框架的父容器 此处是root
# options: 该标签的可设置的属性,以逗号分隔。
# text 设置文本,可以包含换行转义字符
# bg 标签背景颜色
# 设置前景色
# font 设置字体
# w.pack() 调用pack方法,调整其显示位置和大小,pack是按添加顺序排列组件
# side 定义停靠在父组件的哪一边上 “ top ” , “ bottom ” , “left”, “right” (默认为”top”)
# fill 填充 x(y)方向上的空间,当属性 side=”top”或” bottom”时,填充 x 方向
# Python Tkinter Place布局管理器用法:https://www.cnblogs.com/jsdd/articles/11482023.html
# x:指定组件的 X 坐标。x 为 0 代表位于最左边。  y:指定组件的 Y 坐标。y 为 0 代表位于最右边。
Label(root, text='学生成绩管理系统', bg='white', fg='red', font=('宋体', 15)).place(x=430,y=10)
Label(root, text="学号查询" ).place(x=360, y=100)
con = controller()  # 创建控制器对象
data = con.cha('')  # 获取首次全部数据,即首次启动系统显示的数据
def search():  # 模糊查询
    x = tree.get_children()  # 清空所有页面数据
    for i in x:
        tree.delete(i)
    data = con.cha(u.get())  # 获取数据
    for i in range(len(data)):  # 数据输出
        tree.insert('', 'end', values=data[i])
def paiMing():  # 分数排名
    x = tree.get_children()  # 清空所有页面数据
    for i in x:
        tree.delete(i)
    data = con.pai()
    for i in range(len(data)):  # 数据输出
        tree.insert('', 'end', values=data[i])
def baobiao():
    con.biao()  # 调用生成文件报表方法
    tkinter.messagebox.showinfo('已完成', '请查看student.csv文件')  # 弹出消息框确认完成
# 在使用界面编程的时候,有些时候是需要跟踪变量的值的变化,以保证值的变更随时可以显示在界面上。
# 由于python无法做到这一点,所以使用了tcl的相应的对象,也就是StringVar、BooleanVar、DoubleVar、IntVar所需要起到的作用
# StringVar类似于Java中的String
# 设定一个空字符串接收输入的值
# 双向绑定
u = StringVar()
# 通过textvariable来获取框中值
# Tkinter 组件:Entry,Entry(输入框)组件通常用于获取用户的输入文本。
Entry(root, width=20, textvariable=u).place(x=420, y=100)
# Button 控件是一种标准 Tkinter 控件, 用来展现不同样式的按钮.
# Button 控件被用以和用户交互, 比如按钮被鼠标点击后, 某种操作被启动.
# 和 Label 控件类似, 按钮可以展示图片或者文字.
# 不同的是, Label 控件可以指定字体, Button 控件只能使用单一的字体. Button 上的文字可以多行显示.
# command类型:回调;
# 说明:当按钮被按下时所调用的一个函数或方法。所回调的可以是一个函数、方法或别的可调用的Python对象。
Button(root, text="查询", width=8,command=search).place(x=575, y=95)
Button(root, text="成绩排名", width=9, height=4,command=paiMing).place(x=715, y=440)
Button(root, text="生成报表", width=9 , height= 4,command=baobiao).place(x=800, y=440)
# Python tkinter之Treeview用法:https://www.cnblogs.com/rainbow-tan/p/14125768.html
# 设置列表中列的布局,root是父容器,columns定义显示的列,show='headings'用于隐藏首列
tree = tk.Treeview(root, height= 13,columns=['1', '2', '3', '4', '5', '6', '7'], show='headings')
tree.place(x=360, y=140)  # 定义位置
# anchor='w' 定义对齐方式,可选n, ne, e, se, s, sw, w, nw, center
tree.column('1', width=85, anchor='center')
tree.column('2', width=85, anchor='center')
tree.column('3', width=85, anchor='center')
tree.column('4', width=85, anchor='center')
tree.column('5', width=85, anchor='center')
tree.column('6', width=85, anchor='center')
tree.column('7', width=85, anchor='center')
# 设置列表中列的标题
tree.heading('1', text='学号')
tree.heading('2', text='姓名')
tree.heading('3', text='性别')
tree.heading('4', text='数学')
tree.heading('5', text='英语')
tree.heading('6', text='语文')
tree.heading('7', text='总成绩')
for i in range(len(data)):  # 数据输出 页面首次
    tree.insert('', 'end', values=data[i])
def zengjia():
    s = [a.get(), b.get(), c.get(), d.get(), e.get(), f.get()]  # 写入数据源
    for i in range(6):  # 判断输入是否有空值
        if (s[i] == ''):
            tkinter.messagebox.showinfo('信息', '信息不完整')
            break
    else:  # python break 无法跳出两层,需用for()....else...来解决
        con.zeng(s)  # 将数据源交于控制器方法传入数据库
        search()  # 再次查询
a = IntVar()
b = StringVar()
c = StringVar()
d = IntVar()
e = IntVar()
f = IntVar()
Label(root, text="添加数据").place(x=40, y=100)
Label(root, text="学号").place(x=40, y=130)
Entry(root, width=20, textvariable=a).place(x=75, y=130)
Label(root, text="姓名").place(x=40, y=160)
Entry(root, width=20, textvariable=b).place(x=75, y=160)
Label(root, text="性别").place(x=40, y=190)
Entry(root, width=20, textvariable=c).place(x=75, y=190)
Label(root, text="数学").place(x=40, y=220)
Entry(root, width=20, textvariable=d).place(x=75, y=220)
Label(root, text="英语").place(x=40, y=250)
Entry(root, width=20, textvariable=e).place(x=75, y=250)
Label(root, text="语文").place(x=40, y=280)
Entry(root, width=20, textvariable=f).place(x=75, y=280)
Button(root, text="添加", width=9, height=4,bg = "white",command=zengjia).place(x=250, y=170)
# 选中的数据显示至输入框
form_record = []
def show_input():
    global form_record
    print(form_record)
    g.set(form_record[0])
    h.set(form_record[1])
    i.set(form_record[2])
    j.set(form_record[3])
    k.set(form_record[4])
    l.set(form_record[5])
def selectTree(event):  # 表格点击响应函数
    global form_record
    form_record = tree.item(tree.selection(), "values")  # 获得点击的数据
    # 显示至输入框
    show_input()
# Tkinter 之TreeView表格与树状标签:https://www.cnblogs.com/yang-2018/p/11824250.html
# 在bind方法里的'<>'添上相应的事件代码,后面跟定义的函数
#<< TreeviewSelect>>,代表选择变化是发生
tree.bind('<<TreeviewSelect>>', selectTree)  # 绑定点击事件
def gengxin():  # 更新数据
    s = [g.get(), h.get(), i.get(), j.get(), k.get(), l.get()]  # 写入数据源
    con.geng(s)  # 调用更新方法
    search()  # 重新加载数据
def shanchu():  # 删除数据
    n = g.get()
    if (n == ''):
        tkinter.messagebox.showinfo('提示', '请选中学生')
    else:
        con.shan(n)  # 调用删除方法
        search()  # 重新加载数据
g = StringVar()
h = StringVar()
i = StringVar()
j = StringVar()
k = StringVar()
l = StringVar()
Label(root, text="更改数据").place(x=40, y=320)
Label(root, text="学号").place(x=40, y=350)
Entry(root, width=20, textvariable=g).place(x=75, y=350)
Label(root, text="姓名").place(x=40, y=380)
Entry(root, width=20, textvariable=h).place(x=75, y=380)
Label(root, text="性别").place(x=40, y=410)
Entry(root, width=20, textvariable=i).place(x=75, y=410)
Label(root, text="数学").place(x=40, y=440)
Entry(root, width=20, textvariable=j).place(x=75, y=440)
Label(root, text="英语").place(x=40, y=470)
Entry(root, width=20, textvariable=k).place(x=75, y=470)
Label(root, text="语文").place(x=40, y=500)
Entry(root, width=20, textvariable=l).place(x=75, y=500)
Button(root, text="更新", width=9,height = 4 ,command=gengxin).place(x=250, y=380)
Button(root, text="删除信息", width=9,height=4, command=shanchu).place(x=885, y=440)
# mainloop()方法允许程序循环执行,并进入等待和处理事件。
root.mainloop()


数据库设计(Navicat)

/*
 Navicat Premium Data Transfer

 Source Server         : local
 Source Server Type    : MySQL
 Source Server Version : 80027
 Source Host           : localhost:3306
 Source Schema         : mybatis

 Target Server Type    : MySQL
 Target Server Version : 80027
 File Encoding         : 65001

 Date: 21/12/2021 01:39:01
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `sex` char(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `math` int NULL DEFAULT NULL,
  `english` int NULL DEFAULT NULL,
  `chinese` int NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12346 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (1233, '每', '男', 88, 66, 99);
INSERT INTO `student` VALUES (1234, '天', '女', 56, 45, 90);
INSERT INTO `student` VALUES (1235, '起', '男', 70, 60, 80);
INSERT INTO `student` VALUES (1256, '床', '男', 78, 90, 67);
INSERT INTO `student` VALUES (1266, '都', '男', 88, 77, 44);
INSERT INTO `student` VALUES (1789, '想', '女', 54, 54, 56);
INSERT INTO `student` VALUES (1790, '摆', '女', 78, 67, 89);
INSERT INTO `student` VALUES (1791, '作者', '男', 67, 56, 78);
INSERT INTO `student` VALUES (1792, '简书', '男', 78, 67, 78);

SET FOREIGN_KEY_CHECKS = 1;

实现(设计作者隐私,部分数据已涂抹)

系统预览图与背景图原图


屏幕截图 2022-01-01 205156.png

img.gif

附结课答辩知识点

1.def add():
判断要添加的5个字段是否为空【add_check】。
通过Stringvar从组件entry中取出用户输入的值。
判断要添加的学号是否【exists】,若存在弹出messagebox提示框。
否则,操作数据库文件,insert into5个字段。
插入数据后,将页面【show_all】
考虑非法输入时的错误捕获

2.def update():
通过Stringvar从页面组件entry中取到5个字段的值,并以元组的方式存储。
操作数据库文件,得到当前学号学生的信息,fetchone方法返回一条记录(元组)。
若有值,通过Stringvar将用户在组件entry输入的5个字段值依次set到对应column中。

3.def delete():
messagebox.askokcancel弹出询问是否删除对话框。
通过Stringvar从页面组件entry中get学生学号。
若有值,操作数据库文件,将此学号学生delete。
messagebox.showinfo弹出删除成功对话框。
删除数据后,【show_all】。
并将刚才用户选中的读入entry值都清空(w.set(''))。

4.def search():
通过stringvar从组件entry中get用户输入的学号值。
若为空值,则【show_all】
否则,操作数据库文件获取当前学号对应的item值(元组)。
若item有值,则list(item),并【clear_tree_view】。
在item中insert(0,1)。
对item中的语数外三项成绩求和,并append到item中。
通过tree.insert(模块ttk中的函数,可查看用法),将查询到的一条item插入到treeview组件中(可直接显示在GUI页面中)。
tree.selection_set(),将选中的数据显示出来。
若无值,messagebox.showinfo(),弹窗提示无此学号。

5.def clear_tree_view():
w.get_children()得到所有子节点的数据。
循环遍历删除。

6.def show_all():
先【clear_tree_view】。
操作数据库文件,获取表中所有数据到list。
循环遍历,通过enumerate(list,start=1)处理数据(需要将总成绩求和后append到list,将序号插入后直接将数据insert到treeview中)。

  1. def select():
    通过stringvar将组件entry中的值都set到修改学生信息labelframe中的5个entry中。

8.def order():
操作数据库文件,获取表中所有学生信息,return fetchall(多个元组)。
将返回的元组循环遍历插入到列表中,并append总成绩值。
list.sort()对列表根据总成绩排序。
【clear_tree_view】
循环编列得到的新list,inser到treeview中。

9.def export():
askdirectory()询问要导出的路径。
若有path值:打开或创建文件,并通过csv.writer将数据库表中所有数据都写入到csv文件中。
messagebox.showinfo()弹出框提示导出成功。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容