初写学生管理系统(简易版)

发布于 2019-03-01  6 次阅读


这次实训周意味着学校的python的课程进入结尾了,虽然我很期待学习java,但期待归期待,python算是我第一门正式接触的编程语言,有着其他语言没有的感情,虽然我学的语言不多,无法体会到python的方便,但学无止尽嘛,回头学多了就更加清楚了,这门课程结束也不是说我会把python丢一边,后续有时间的话打算用python学习一下久仰的爬虫。

  这次的学生管理系统,学到tkinter的入门使用,在用的过程中我老是想到前端的那点微薄知识,上学期末的的贪吃蛇也是,很直观的感受就是界面设计都是一样似的,绝对定位、相对定位、宽、高等属性都在变相打包成模块能提供给对应的语言使用,没学太深,具体的区别就不清楚了,流程大概都是创建一个跟窗口,把大大小小的组件放在上面的,用属性描绘除自己想要的样式,变量绑定,交互上的函数调用....

  这次用到的包有tkinter、内置数据库sqlite3、内置包logging、第三方包xlwt。Tkinter这个包用来写UI,sqlite3用来储存学生、科目等的信息,logging用来记录日志,xlwt用来将学生的成绩输出一个excel文件,废话不多说,附上全部代码
  

from tkinter import *
from tkinter.messagebox import askokcancel,showinfo
from sqlite3 import *
from tkinter.ttk import Combobox,Treeview
import logging
import xlwt

cn = connect("student.db")  # 如果数据库已经存在,就获得数据库的连接,不存在就建立数据库并获得连接

#--------------------------------------------------【数据库的创建与删除】---------------------------------------------------
# 建立数据表,一个相同的表只需执行一次
# cn.execute('create table stu(sid varchar(6) primary key,sname varchar(8),age int(3),tel varchar(11))') # 存放学生信息
# cn.execute('create table subject(id varchar(6) primary key,name varchar(50))')  # 存放科目信息
# cn.execute('create table score(uid varchar(6),sid varchar(6),grade int(3))') # 存放成绩信息
# cn.execute('drop table score')  # 删除数据表
#-----------------------------------------------------------------------------------------------------------------------

root = Tk()  # 创建根窗口
sysTitle = '学生信息管理系统'  # 系统标题
operate_frame = Frame()  # 没有指定的情况下默认父窗口为根窗口
operate_frame.pack(anchor=CENTER, pady=50, ipadx=5, ipady=5)  # 使用用Packer布局

# 主函数
def main():
    root.geometry('600x400')  # 设置窗口初始大小
    root.title(sysTitle)  # 设置系统标题
    # 创建系统菜单
    menu_bar = Menu(root)  # 创建Menu对象menuBar,将作为root窗口中的菜单
    root.config(menu=menu_bar)  # 将menuBar菜单作为root窗口的顶层菜单栏

    # 学生信息管理菜单——该模块是创建一个在menuBar上名为menu_student的对象,在menu_student上添加    label,然后把menu_student添加到menuBar上,添加的顺序可颠倒,下面的学生成绩管理菜单等也是这样
    menu_student = Menu(menu_bar, tearoff=0)  # menu_student将作为menuBar菜单的子菜单
    menu_student.add_command(label='显示全部学生信息', font=('宋体', 10),     command=show_all_student)
    menu_student.add_command(label='查找/修改学生信息', font=('宋体', 10),     command=check_update_student)
    menu_student.add_command(label='添加新学生', font=('宋体', 10), command=add_student)
    menu_student.add_separator()
    menu_student.add_command(label='退出', font=('宋体', 10), command=goe_xit)
    menu_bar.add_cascade(label='个人信息管理', font=('宋体', 10), menu=menu_student)  # 菜单file添加为menuBar的子菜单

    # 学生科目管理菜单
    menu_subject = Menu(menu_bar, tearoff=0)  # menu_student将作为menuBar菜单的子菜单
    menu_subject.add_command(label='显示全部科目', font=('宋体', 10), command=show_all_subject)
    menu_subject.add_command(label='查找/修改/删除科目', font=('宋体', 10),     command=check_update_subject)
    menu_subject.add_command(label='添加新科目', font=('宋体', 10), command=add_subject)
    menu_bar.add_cascade(label='科目管理', font=('宋体', 10), menu=menu_subject)  # 菜单file添    加为menuBar的子菜单

    # 学生成绩管理菜单
    menu_score = Menu(menu_bar, tearoff=0)  # menu_score将作为menuBar菜单的子菜单
    menu_search = Menu(menu_bar, tearoff=0)  # menu_score将作为menuBar菜单的子菜单
    menu_bar.add_cascade(label='成绩管理', font=('宋体', 10), menu=menu_score)
    menu_score.add_command(label='录入成绩', font=('宋体', 10), command=input_score1)
    menu_score.add_cascade(label='查询成绩', font=('宋体', 10), menu=menu_search)
    menu_search.add_command(label='按照科目编号', font=('宋体', 10),     command=show_score_subject)
    menu_search.add_command(label='按照学生学号', font=('宋体', 10), command=show_score_id)
    menu_score.add_command(label='成绩输出为excel表', font=('宋体', 10), command=output_excel)

    # 帮助菜单
    menu_help = Menu(menu_bar, tearoff=0)  # help将作为menuBar菜单的子菜单
    menu_help.add_command(label='查看日志', font=('宋体', 10), command=show_log)
    menu_help.add_command(label='关于...', font=('宋体', 10), command=show_about)
    menu_bar.add_cascade(label='帮助', font=('宋体', 10), menu=menu_help)  # 菜单help添加为    menuBar的子菜单
    root.mainloop()

# 每次调用新的模块函数时,都需要吧前一个的调用的函数所产生的界面destory后再创建一个,为了减少代码沉余而创建了该函数
def re_use_frame():
    global operate_frame
    operate_frame.destroy()
    operate_frame = Frame()
    operate_frame.pack()

#-----------------------------------------------------【学生信息管理菜单模块】----------------------------------------------

# 显示所有学生
def show_all_student():
    re_use_frame()
    # 滚轮组件经常和Listbox,canvas,等组合着用,但考虑到Listbox的观赏性没有canvas    高,所以这里用canvas
    canvas = Canvas(operate_frame)
    frame = Frame(canvas)

    # 设置frame窗口的列数和宽度
    frame.columnconfigure(1, minsize=100)
    frame.columnconfigure(2, minsize=100)
    frame.columnconfigure(3, minsize=100)
    frame.columnconfigure(4, minsize=100)
    frame.columnconfigure(5, minsize=100)

    # 表头
    Label(frame, text='学号',font=('宋体', 10, 'bold'), bd=1,).grid(row=0,     column=2, sticky=W)
    Label(frame, text='姓名',font=('宋体', 10, 'bold'), bd=1,).grid(row=0,     column=3, sticky=W)
    Label(frame, text='年龄',font=('宋体', 10, 'bold'), bd=1,).grid(row=0,     column=4, sticky=W)
    Label(frame, text='电话',font=('宋体', 10, 'bold'), bd=1,).grid(row=0,     column=5, sticky=W)

    # 从数据库stu表中渠道所有学生的数据,返回一个列表
    stu_list = cn.execute('select * from stu').fetchall()

    # 设置滚动条
    myscrollbar = Scrollbar(operate_frame, orient="vertical",     command=canvas.yview)
    canvas.configure(yscrollcommand=myscrollbar.set)
    myscrollbar.pack(side="right", fill="y")  # 用packer布局

    canvas.pack()
    canvas.create_window((0, 0), window=frame, anchor='nw')

    # 遍历列表
    row_num = 1
    for stu in stu_list:
        col_num = 2
        for info in stu:
            Label(frame, text=str(info), font=('宋体', 10), bd=1, ).grid(row=row_num, column=col_num,sticky=W)
            col_num += 1
        row_num += 1
    # 设置canvas的滚动时调用的函数
    def myfunction(event):
        canvas.configure(scrollregion=canvas.bbox("all"), width=600, height=400)
    # 回调
    frame.bind("<Configure>", myfunction)
    # 记录日志
    write_log("查看了所有学生信息")

# 查看、修改、删除学生
def check_update_student():
    re_use_frame()

    f1 = Frame(operate_frame)
    f1.pack(anchor=CENTER, pady=20, ipadx=5, ipady=5)

    # 创建一个标签、输入框、Button三个组件,用Grid布局放在f1中
    Label(f1, text='请输入要查找学生的学号:',anchor=E).grid(row=1, column=1)
    idToFind = StringVar()
    txtidToFind = Entry(f1, textvariable=idToFind)  # 绑定输入的内容对象    idToFind
    txtidToFind.grid(row=1, column=2)
    comfirm = Button(f1, text='确定')
    comfirm.grid(row=1, column=3)

    f2 = Frame(operate_frame)
    f2.pack(anchor=CENTER, pady=40, ipadx=5, ipady=5)

    op = LabelFrame(f2, text='修改学生:')
    op.pack(anchor=CENTER, pady=10, ipadx=5, ipady=5)

    Label(op, text='学号:',anchor=E).grid(row=1, column=1)

    # 创建一个输入框组件,与其内容的对象进行绑定,最后用Grid布局放在op中,下面的姓    名,年龄,电话,都是一样的思路
    sid = StringVar()
    txtid = Entry(op, textvariable=sid)
    txtid.grid(row=1, column=2)

    Label(op, text='姓名:',anchor=E).grid(row=2, column=1, sticky=E)
    sname = StringVar()
    txtname = Entry(op, textvariable=sname)
    txtname.grid(row=2, column=2)

    Label(op, text='年龄:',anchor=E).grid(row=3, column=1, sticky=E)
    sage = StringVar()
    txtage = Entry(op, textvariable=sage)
    txtage.grid(row=3, column=2)

    Label(op, text='电话:',anchor=E).grid(row=4, column=1, sticky=E)
    tel = StringVar()
    txttel = Entry(op, textvariable=tel)
    txttel.grid(row=4, column=2)

    #创建一个按钮,初始状态设置为disabled,当调用dofind时候找到学生,状态转为    normal--->Line188
    info_save = Button(op, text='保存修改', state=DISABLED)
    info_save.grid(row=4, column=3, sticky=N + E + S + W)

    # 查找
    def do_find():
        idfind = idToFind.get()
        stuFound = cn.execute('select * from stu where sid = ?', (idfind,))  .fetchone()
        if not stuFound:
            showinfo(sysTitle, "学生不存在!")
            idToFind.set('')
        else:  # 查找到学生,像信息放入输入框
            sid.set(stuFound[0])
            sname.set(stuFound[1])
            sage.set(str(stuFound[2]))
            tel.set(stuFound[3])
            info_save.config(state=NORMAL)

        # 记录日志
        write_log("查找了学号:"+sid.get()+"|姓名:"+sname.get()+"的学生信息")

    # 保存学生信息
    def do_save():
        cn.execute('update stu set sid = ?, sname = ?, age = ?, tel = ? where sid=?', (sid.get(),sname.get(),sage.get(),tel.get(),idToFind.get()))
        cn.commit()
        idfind = idToFind.get()
        stuFound = cn.execute('select sid,sname from stu where sid = ?',     (idfind,)).fetchone()
        showinfo('学生信息管理系统', '修改成功')
        info_save.config(state=DISABLED)
        # 记录日志
        write_log("修改了学号:" + stuFound[0] + "|姓名:" + stuFound[1] + "的学生信息")

    # 对按钮进行绑定函数
    comfirm.config(command=do_find)
    info_save.config(command=do_save)

# 添加学生
def add_student():
    re_use_frame()
    f1 = Frame(operate_frame)
    f1.pack(anchor=CENTER, pady=20, ipadx=5, ipady=5)

    Label(f1, text='学号:', font=('宋体', 10, 'bold'), anchor=E).grid(row=1,column=1)   # 创建一个标签组件,用grid布局放在f1里
    id_var = StringVar()
    txt_uid = Entry(f1, textvariable=id_var, font=('宋体', 10, 'bold'))   #  创建一个文本框组件
    txt_uid.grid(row=1, column=2)   # 用grid布局放在f1中                                             下面以此类推

    Label(f1, text='姓名:', font=('宋体', 10, 'bold'), anchor=E).grid(row=2, column=1, sticky=E)
    name_var = StringVar()
    txt_name = Entry(f1, textvariable=name_var, font=('宋体', 10, 'bold'))
    txt_name.grid(row=2, column=2)

    Label(f1, text='年龄:', font=('宋体', 10, 'bold'), anchor=E).grid(row=3, column=1, sticky=E)
    age_var = StringVar()
    txt_age = Entry(f1, textvariable=age_var, font=('宋体', 10, 'bold'))
    txt_age.grid(row=3, column=2)

    Label(f1, text='电话:', font=('宋体', 10, 'bold'), anchor=E).grid(row=4, column=1, sticky=E)
    tel_var = StringVar()
    txt_tel = Entry(f1, textvariable=tel_var, font=('宋体', 10, 'bold'))
    txt_tel.grid(row=4, column=2)

    f2 = Frame(operate_frame)
    f2.pack()
    bt_clear = Button(f2, text='重置', font=('宋体', 10, 'bold'))
    bt_clear.grid(row=1, column=1)
    bt_ok = Button(f2, text='保存', font=('宋体', 10, 'bold'))
    bt_ok.grid(row=1, column=2)
    # 重置
    def reset():
        id_var.set('')
        name_var.set('')
        age_var.set(0)
        tel_var.set('')
    # 保存
    def preserve():
        # 对信息进行检索,看看是否符合要求
            student_id = id_var.get()
            if not len(student_id) == 9:
                raise
            student_name = name_var.get()
            student_age = age_var.get()
            if not student_age.isdigit():
                raise
            else:
                student_age = int(student_age)
                if student_age <10 or student_age > 50:
                    raise
            student_tel = tel_var.get()
            if not student_tel.isdigit():
                raise
            # 吧数据存入数据库
            cn.execute('insert into stu values(?,?,?,?)',(student_id,student_name,student_age,student_tel))
            cn.commit() # 提交数据到SQLite数据库

            # 为了验证信息是否真的录入数据库,用一下语句来读取数据库的stu表的全部信息
            # stu_list = cn.execute('select * from stu').fetchall()
            # print(stu_list)

            showinfo("学生管理系统","学生信息成功保存")
            # 记录日志
            write_log("添加了学号:" + student_id + "|姓名:" + student_name + "的学生信息")
            reset()
        except:
            showinfo("学生管理系统","数据类型或者数字个数出错,请重新输入",)

    # 对按钮和函数进行绑定
    bt_clear.config(command=reset)
    bt_ok.config(command = preserve)

# 退出
def goe_xit():
    if askokcancel('学生信息管理系统','确定退出系统?'):
        exit(0)

#-------------------------------------【学生科目管理菜单模块(与学生管理信息模块相似,不多赘述)】---------------------------------

# 显示所有科目
def show_all_subject():
    re_use_frame()
    canvas = Canvas(operate_frame)
    frame = Frame(canvas)

    frame.columnconfigure(1, minsize=100)
    frame.columnconfigure(2, minsize=100)
    frame.columnconfigure(3, minsize=100)
    frame.columnconfigure(4, minsize=100)

    # 表头
    Label(frame, text='编号', font=('宋体', 10, 'bold'), bd=1, ).grid(row=0, column=3, sticky=W)
    Label(frame, text='科目', font=('宋体', 10, 'bold'), bd=1, ).grid(row=0, column=4, sticky=W)

    stu_list = cn.execute('select * from subject').fetchall()

    # 设置滚动条
    myscrollbar = Scrollbar(operate_frame, orient="vertical", command=canvas.yview)
    canvas.configure(yscrollcommand=myscrollbar.set)
    # 布局
    myscrollbar.pack(side="right", fill="y")
    canvas.pack()
    canvas.create_window((0, 0), window=frame, anchor='nw')
    # 遍历列表
    row_num = 1
    for stu in stu_list:
        col_num = 3
        for info in stu:
            Label(frame, text=str(info), font=('宋体', 10), bd=1, ).grid(row=row_num, column=col_num, sticky=W)
            col_num += 1
        row_num += 1
    def myfunction(event):
        canvas.configure(scrollregion=canvas.bbox("all"), width=600, height=400)
    # 回调
    frame.bind("<Configure>", myfunction)
    # 写日志
    write_log("查看了所有科目")

# 查看、修改、删除科目
def check_update_subject():
    re_use_frame()
    f1 = Frame(operate_frame)  # label默认放在左边
    f1.pack(anchor=CENTER, pady=30, ipadx=5, ipady=5)

    Label(f1, text='请输入要查找科目编号:', anchor=E).grid(row=1, column=1)  # 标签

    idToFind = StringVar()
    txtidToFind = Entry(f1, textvariable=idToFind)                         # 输入框
    txtidToFind.grid(row=1, column=2)

    # 创建一个Button组件,用Grid布局放在f1中
    comfirm = Button(f1, text='确定')                                      # 按钮
    comfirm.grid(row=1, column=3)

    f2 = Frame(operate_frame)
    f2.pack(anchor=CENTER, pady=40, ipadx=5, ipady=5)

    op = LabelFrame(f2, text='修改科目:')
    op.pack(anchor=CENTER, pady=10, ipadx=5, ipady=5)

    # Label组件
    Label(op, text='科目编号:', anchor=E).grid(row=1, column=1)            # 标签

    sid = StringVar()
    txtid = Entry(op, textvariable=sid)                                   # 输入框
    txtid.grid(row=1, column=2)

    Label(op, text='科目:', anchor=E).grid(row=2, column=1, sticky=E)     # 输入框
    sname = StringVar()
    txtname = Entry(op, textvariable=sname)
    txtname.grid(row=2, column=2)

    info_save = Button(op, text='保存修改', state=DISABLED)                 # 按钮
    info_save.grid(row=3, column=3, sticky=N + E + S + W)

    info_delete = Button(op, text='删除科目', state=DISABLED)               # 按钮
    info_delete.grid(row=3, column=1, sticky=N + E + S + W)

    # 查找科目
    def do_find():
        idfind = idToFind.get()
        stuFound = cn.execute('select * from subject where id = ?', (idfind,)).fetchone()
        if not stuFound:
            showinfo(sysTitle, "该科目不存在!")
            idToFind.set('')
        else:  # 信息放在输入框中
            sid.set(stuFound[0])
            sname.set(stuFound[1])
            info_delete.config(state=NORMAL)
            info_save.config(state=NORMAL)

        write_log("查找了编号:" + sid.get() + "|名为:" + sname.get() + "的科目") # 记录日志

    # 删除科目
    def do_delete():
        idfind = idToFind.get()
        if askokcancel('学生信息管理系统', "确认删除科目?"):
            cn.execute('delete from subject where id=?', (idfind,))
            cn.commit()
            showinfo(sysTitle, "成功删除科目。")
            sid.set('')
            sname.set('')
            info_delete.config(state=DISABLED)
            info_save.config(state=DISABLED)

        write_log("删除了原编号:" + idfind + "的科目")                          # 记录日志

    # 对科目进行修改
    def do_save():
        cn.execute('update subject set id = ?, name = ? where id=?',(sid.get(), sname.get(), idToFind.get()))
        cn.commit()
        showinfo('学生信息管理系统', '修改成功')
        info_delete.config(state=DISABLED)
        info_save.config(state=DISABLED)
        idfind = idToFind.get()
        # 读取刚修改的数据
        stuFound = cn.execute('select name from subject where id = ?', (idfind,)).fetchone()

        write_log("将编号:" + stuFound[0] + "|名为:" + stuFound[1] + "的科目进行修改") # 记录日志

    # 对按钮进行绑定
    comfirm.config(command=do_find)
    info_save.config(command=do_save)
    info_delete.config(command=do_delete)

# 添加科目
def add_subject():
    re_use_frame()
    f1 = Frame(operate_frame)
    f1.pack(anchor=CENTER, pady=60, ipadx=5, ipady=5)

    Label(f1, text='科目编号:', font=('宋体', 10, 'bold'), anchor=E).grid(row=1, column=1)        # 标签
    id_var = StringVar()
    txt_uid = Entry(f1, textvariable=id_var, font=('宋体', 10, 'bold'))                          # 输入框
    txt_uid.grid(row=1, column=2)

    Label(f1, text='科目:', font=('宋体', 10, 'bold'), anchor=E).grid(row=2, column=1, sticky=E) # 标签
    name_var = StringVar()
    txt_name = Entry(f1, textvariable=name_var, font=('宋体', 10, 'bold'))                       # 输入框
    txt_name.grid(row=2, column=2)

    f2 = Frame(operate_frame)
    f2.pack()
    bt_clear = Button(f2, text='重置', font=('宋体', 10, 'bold'))                                # 按钮
    bt_clear.grid(row=1, column=1)
    bt_ok = Button(f2, text='保存', font=('宋体', 10, 'bold'))                                   # 按钮
    bt_ok.grid(row=1, column=2)

    # 重置
    def reset():
        id_var.set('')
        name_var.set('')

    # 保存
    def preserve():
        # 吧数据存入数据库
        cn.execute('insert into subject values(?,?)',(id_var.get(),name_var.get()))
        cn.commit() # 提交数据到SQLite数据库
        # 为了验证信息是否真的录入数据库,用一下语句来读取数据库的stu表的全部信息
        stu_list = cn.execute('select * from subject').fetchall()
        print(stu_list)

        showinfo("学生管理系统","添加科目成功")
        # 记录日志
        write_log("添加了编号为:" + id_var.get() + "|名为:" + name_var.get() + "的科目")
        reset()

    # 对按钮进行绑定
    bt_clear.config(command=reset)
    bt_ok.config(command = preserve)

#-----------------------------------------------------------------------------------------------------------------------

#-------------------------------------------------【学生成绩管理菜单模块】--------------------------------------------------

# 录入成绩
def input_score1():
    re_use_frame()

    student_list = []    # 用来存放学生名单
    score_var_list = []  # 用来存放输入框的变量值

    f1 = Frame(operate_frame)
    f2 = Frame()
    f1.pack()

    Label(f1, text='科目名称:').grid(row=1, column=1)   # 标签
    subject_name_combobox = Combobox(f1)               # 下拉列表组件
    subject_name_combobox.grid(row=1, column=2)
    bt_save = Button(f1, text='保存成绩')               # 按钮
    bt_save.grid(row=1, column=3)

    # 从数据库取到所有科目的编号,名称,分别得到两个列表
    subject_list = cn.execute('select id,name from subject').fetchall()
    subject_name_list = []  # 科目名称的列表
    subject_id_list = []  # 科目编码的列表,两个列表下标一一对应
    for i in subject_list:
        subject_id_list.append(i[0])
        subject_name_list.append(i[1])

    subject_name_combobox["values"] = subject_name_list

    # 当选中科目时,打开f2窗口
    def go(*args):
        nonlocal student_list
        nonlocal score_var_list
        nonlocal f2  # 解决f2多次出现的问题

        f2.destroy()
        f2 = Frame(operate_frame)
        f2.pack()

        f2.columnconfigure(1, minsize=80)
        f2.columnconfigure(2, minsize=80)
        f2.columnconfigure(3, minsize=80)

        # 表头
        Label(f2, text='学号', font=('宋体', 10, 'bold'), ).grid(row=0, column=1, sticky=W)
        Label(f2, text='姓名', font=('宋体', 10, 'bold'), ).grid(row=0, column=2, sticky=W)
        Label(f2, text='成绩', font=('宋体', 10, 'bold'), ).grid(row=0, column=3, sticky=W)

        student_list = cn.execute('select sid,sname from stu ').fetchall()
        score_var_list = []  # 依次存入每个学生的控制变量

        subject_id_choose = subject_id_list[subject_name_list.index(subject_name_combobox.get())]       # 获得当前课程的编号

        score_currentsub_list = cn.execute('select uid,grade from score where uid = ?', (subject_id_choose,)).fetchall()# 取出当前课程的所有    成绩

        row_num = 1
        for stu in student_list:
            column_num = 1
            for i in stu:  # 输出一个学生的学号、姓名
                Label(f2, text=str(i)).grid(row=row_num, column=column_num, sticky=W)
                column_num += 1
            # 输出一个录入成绩的文本框
            score_var = StringVar()  # 不能用IntVar,因为不能初始为0
            score_var_list.append(score_var)
            Entry(f2, textvariable=score_var).grid(row=row_num, column=column_num)
            # 把之前录入过的成绩显示在这个entry中
            for j in score_currentsub_list:
                if j[0] == stu[0]:
                    score_var.set(j[1])

            row_num += 1

        # 输出每个分数
        for i in score_var_list:
            print(i.get())
    # 下拉列表绑定函数
    subject_name_combobox.bind("<<ComboboxSelected>>", go)

    # 保存
    def save():
        nonlocal student_list  # 此列表已经在go函数中存入了学号和姓名
        nonlocal score_var_list

        i = subject_name_list.index(subject_name_combobox.get())    # 取到当前课程的编号
        subject_id = subject_id_list[i]

        cn.execute('delete from score where sid = ?', (subject_id,)) # 保存之前,先把当前课程的所有成绩删除
        # 向数据表score插入学号、科目编号、成绩
        i = 0
        for s in student_list:
            score_v = score_var_list[i].get().strip()
            print('s:', score_v)
            if not score_v == '':
                print(s[0])
                cn.execute('insert into score values(?,?,?)', (s[0], subject_id, int(score_v)))
            i += 1
        # 对数据库进行insert处理后都得进行commit
        cn.commit()

        showinfo("学生管理系统", '保存成功!')
        # # 记录日志
        # record_info = cn.execute('select sname from stu where sid = ?', (s[0],)).fetchall()
        # # 测试语句
        # # print(record_info[0][0])
        # logging.info(write_log()("为"+record_info[0][0]+"录入了" + subject_name_combobox.get() + "这一科目的学生成绩"))

    # 对按钮进行绑定
    bt_save.config(command=save)

# 由科目来查询成绩
def show_score_subject():
    re_use_frame()

    f1 = Frame(operate_frame)
    f1.pack()

    f1.columnconfigure(1, minsize=80)
    f1.columnconfigure(2, minsize=100)
    f1.columnconfigure(3, minsize=100)

    f2 = Frame()

    Label(f1, text='学号').grid(row=0, column=1)  # 标签
    subject_name_combobox = Combobox(f1)         # 下拉列表
    subject_name_combobox.grid(row=0, column=2)
    search_score = Button(f1, text='查询')       # 按钮
    search_score.grid(row=0, column=3)
# -------------------------------------------------------------------------------与录入成绩的一样
    subject_list = cn.execute('select id,name from subject').fetchall()
    subject_name_list = []  # 科目名称的列表
    subject_id_list = []  # 科目编码的列表,两个列表下标一一对应
    for i in subject_list:
        subject_id_list.append(i[0])
        subject_name_list.append(i[1])
    ------------------------------------------------------------------------------
    subject_name_combobox["values"] = subject_name_list

    def tofind():
        nonlocal f2
        f2.destroy()
        f2 = Frame(operate_frame)
        f2.pack()

        f2.columnconfigure(1, minsize=150)
        f2.columnconfigure(2, minsize=100)
        f2.columnconfigure(3, minsize=100)
        f2.columnconfigure(4, minsize=150)

        Label(f2, text='科目').grid(row=0, column=1)
        Label(f2, text='学号').grid(row=0, column=2)
        Label(f2, text='姓名').grid(row=0, column=3)
        Label(f2, text='成绩').grid(row=0, column=4)

        sql = 'select subject.name,stu.sid, stu.sname,score.grade from subject,stu,score '
        sql = sql + 'where stu.sid = score.uid  and subject.id = score.sid and subject.name =?'
        target_id_name = cn.execute(sql, (subject_name_combobox.get(),)).fetchall()

        row_num = 1
        for info in target_id_name:
            column_num = 1
            for i in info:  # 输出一个学生的学号、姓名
                Label(f2, text=str(i)).grid(row=row_num, column=column_num)
                column_num += 1
            row_num += 1

        write_log("查询了" + subject_name_combobox.get() + "这一科目的所有学生成绩")  # 记录日志
    # 对按钮进行绑定
    search_score.config(command=tofind)

# 由学生ID来查询成绩
def show_score_id():
    re_use_frame()

    f1 = Frame(operate_frame)
    f2 = Frame()
    f1.pack()

    f1.columnconfigure(1, minsize=80)
    f1.columnconfigure(2, minsize=100)
    f1.columnconfigure(3, minsize=100)

    Label(f1, text='学号').grid(row=0, column=1)                  # 标签
    student_id = StringVar()
    Entry(f1, textvariable=student_id).grid(row=0, column=2)     # 输入框
    search_score = Button(f1, text='查询')                       # 按钮
    search_score.grid(row=0, column=3)

    # 查找
    def tofind():
        nonlocal f2
        f2.destroy()
        f2 = Frame(operate_frame)
        f2.pack()

        f2.columnconfigure(1, minsize=150)
        f2.columnconfigure(2, minsize=100)
        f2.columnconfigure(3, minsize=100)
        f2.columnconfigure(4, minsize=150)

        Label(f2, text='学号').grid(row=0, column=1)
        Label(f2, text='姓名').grid(row=0, column=2)
        Label(f2, text='科目').grid(row=0, column=3)
        Label(f2, text='成绩').grid(row=0, column=4)

        sql = 'select stu.sid,stu.sname, subject.name,score.grade from stu,subject,score '
        sql = sql + 'where stu.sid = score.uid  and subject.id = score.sid and stu.sid =?'
        target_id_name = cn.execute(sql, (student_id.get(),)).fetchall()

        row_num = 1
        for info in target_id_name:
            column_num = 1
            for i in info:  # 输出一个学生的学号、姓名
                Label(f2, text=str(i)).grid(row=row_num, column=column_num)
                column_num += 1
            row_num += 1

        write_log("查询了学号:" + student_id.get() + "|名为:" + info[1] + "的科目成绩")    # 记录日志
    # 对按钮进行绑定
    search_score.config(command=tofind)

# 将成绩输入为excel格式
def output_excel():
    re_use_frame()

    operate_frame.columnconfigure(1, minsize=100)
    operate_frame.columnconfigure(2, minsize=100)
    operate_frame.columnconfigure(3, minsize=100)

    Label(operate_frame,text="请选择要生成的科目名称").grid(row=0,column=1)
    subject_var = StringVar()
    optional_list = Combobox(operate_frame,textvariable=subject_var)
    optional_list.grid(row=0,column=2)
    target_list = cn.execute('select name from subject').fetchall()
    optional_list["values"] = target_list

    onclick_button = Button(operate_frame,text="确认")
    onclick_button.grid(row=0,column=3)
    def onclick():

        # 从数据库读取需要的数据(学号,姓名,科目,成绩)
        sql = 'select stu.sid,stu.sname,subject.name,score.grade from stu,subject,score '
        sql = sql +'where subject.name = ?'
        targer_list = cn.execute(sql,(subject_var.get(),)).fetchall()
        filename = xlwt.Workbook()                # 创建一个excel文件
        sheet = filename.add_sheet("学生成绩单")   # 给文件命名
        startx = 1                               # 初始行为第二行
        for per_target in targer_list:
            starty = 1                           # 初始列为第二列
            for final_target in per_target:
                # 写入的内容
                content = final_target
                # 从第一行第一列开始放进内容
                sheet.write(startx, starty, content)
                starty += 1
            startx += 1
        # 指定储存路径,如果当前路径存在同名文件,会覆盖掉同名文件
#--------------------------------------------------------------------------
        filename.save("D:/pycharm/Practice_Week/Student_Core_List.xls")   # 根据个人电脑路径设置不一,请修改excel文件存储的路径
#--------------------------------------------------------------------------
        showinfo("创建excel表","成功打印")
    # 对按钮进行绑定
    onclick_button.config(command=onclick)

#----------------------------【帮助模块】----------------------------------

# 写日志
def write_log(info=''):
    logging.basicConfig(level=logging.INFO, format="%(asctime)s:%(message)s", filename="log_record.log")
    logging.info(info)

# 查看日志
def show_log():
    re_use_frame()
    # 打开读取的方式文件,没有就创建
    f = open('log_record.log', 'r')

    search_log = Button(operate_frame,text="查看日志")     # 按钮
    search_log.pack()

    def onclick():
        # 设置滚动条
        re_use_frame()
        def myfunction(event):
            canvas.configure(scrollregion=canvas.bbox("all"), width=600, height=400)
        # 为了日志过多能滚动而设置的canvas
        canvas = Canvas(operate_frame)
        frame = Frame(canvas)

        myscrollbar = Scrollbar(operate_frame, orient="vertical", command=canvas.yview)
        canvas.configure(yscrollcommand=myscrollbar.set)

        myscrollbar.pack(side="right", fill="y")
        canvas.pack()
        canvas.create_window((0, 0), window=frame, anchor='nw')
        frame.bind("<Configure>", myfunction)
        lines = f.readlines()
        for eachline in lines:
            Label(frame, text=eachline).grid()      # 日志放在标签以文本的形式用packer布局放在屏幕上
    # 对按钮进行绑定
    search_log.config(command=onclick)

# 关于
def show_about():
    re_use_frame()
    Label(operate_frame).pack()
    Label(operate_frame).pack()
    Label(operate_frame).pack()
    Label(operate_frame).pack()
    Label(operate_frame,text='学生管理系统').pack()
    Label(operate_frame,text='By 两仪猿').pack()
    Label(operate_frame,text='Version 2.1').pack()

#-------------------------------------------------------------------------

if __name__ == '__main__':
    main()

或多或少有些BUG,但只能等腾出空来再来修改修改了(疯狂立Flag!!!)!