zl程序教程

您现在的位置是:首页 >  其他

当前栏目

自助图书馆系统-Tkinter界面和openpyxl表格综合设计案例

案例系统 设计 界面 表格 综合 tkinter 自助
2023-09-11 14:16:57 时间

本案例综合openpyxl(表格)模块和tkinter模块,设计自助图书馆系统,实现读者能够在系统界面“借书”、“还书”、“查询”等操作。

一、界面效果

自助图书馆实现效果
相关数据表格“Data.xlsx”内容如下:
Data.xlsx
功能备注:该表格能够记录读者的账号信息(包括读者号、账号密码)。登录的时候需要调取读者信息进行登录;借书的时候,将借阅书籍登记到读者的借阅记录中;还书的时候,把归还的图书从读者的借阅记录中删掉;查询的时候,能够从表格中获取读者的借阅记录显示在界面。Openpyxl模块对表格的操作可查看之前写过的文章Openpyxl表格模块操作

二、开发环境

Windows10+python3.5.5+Vs Code(开发工具)

三、开发准备

Data.xlsx表格(见文章最后,附完整程序和表格链接)

四、实现过程

  1. 导入库函数。
from tkinter import *
import openpyxl
import tkinter.messagebox as messagebox  #消息弹窗
  1. 主界面程序设计
    *(主界面程序放在最后,这里提前解释)*主界面设计结构简单,就放置了一个“读者登录”按钮,用于读者登录时使用,链接函数Sign_in。这个界面基于main_frame框架,后面要出现新的界面,就将这个框架隐藏起来,重新设置新的框架放置组件。然后设置所有书籍为一个嵌套字典book_sum,方便之后统一读取每一本书籍。最后是表格操作。
#主界面程序
top = Tk()
top.title("图书馆")
top.geometry("800x500")
main_frame = Frame(top)  #主界面框架
main_frame.place(relwidth=1,relheight=1)
#布局主界面标签,按钮:借书、还书、查询、办理读者证、退出系统
Label(main_frame,text = "便民图书馆",font = ("黑体",50),width = 23,height = 3).place(x=0,y = 0)
Button(main_frame,text = "读者登录",bg = "SkyBlue",command = Sign_in,font = ("黑体",15),width = 20,height = 3).place(x= 300,y = 350)
path = "C:/Users/cos(Lin)/Desktop/"  #存放路径,根据实际情况修改
#全部书籍
book_sum = {"文学":{0:"我与地坛",1:"羊脂球",2:"人生",3:"呼兰河传",4:"故乡",5:"边城",6:"朝花夕拾",7:"围城"},
            "计算机":{0:"人工智能基础",1:"Python编程与机器人",2:"人工智能入门",3:"人工智能应用实战",4:"深度学习",5:"计算机网络",6:"机器学习",7:"微信小程序开发"},
            "历史":{0:"万历十五年",1:"中国通史",2:"明朝那些事",3:"全球通史",4:"苏东坡传",5:"显微镜下的大明",6:"南北战争三百年",7:"宋徽宗"},
            "法律":{0:"论犯罪与刑罚",1:"大国宪制",2:"民法总则",3:"民法典",4:"中国法律与中国社会",5:"民法物权",6:"刑法学定律",7:"法律的经济分析"},
            "心理学":{0:"怪诞心理学",1:"乌合之众",2:"蛤蟆先生去看心理医生",3:"社会心理学",4:"心理学史导论",5:"人格心理学",6:"梦的解析",7:"也许你该找个人聊聊"},
            "医学":{0:"传染病学",1:"伤寒杂病论",2:"基础护理学",3:"实用临床药物学",4:"临床诊疗指南_疼痛学分",5:"新编药物学",6:"心电图学",7:"妇产科经典病例分析"}}
#获取第一个工作表:“借阅信息”表的最大行数
sheets = openpyxl.load_workbook(path + "Data.xlsx")
sheet1 = sheets[sheets.sheetnames[0]] 
max_row1 = sheet1.max_row  #获取表格有效值的最后一行的行数,作为读者的编号  
top.mainloop()  #消息循环

主界面的效果如下图:
在这里插入图片描述

  1. 设计登录界面Sign_in函数
    登录界面首先隐藏主界面框架main_frame,然后布局新的框架组件second_frame框架组件,在框架里面放置“读者号”、“账号密码”的文本输入框组件,用于读者输入相关的信息。然后放置确认按钮,关联functions函数(服务功能),传递的参数有本界面的框架组件和读者输入的两个信息,用于后面获取。
#登录界面
def Sign_in():
    #隐藏第一个界面,设置第二个界面
    main_frame.place_forget()
    second_frame = Frame(top)
    second_frame.place(relwidth=1,relheight=1)  
    #在界面显示“读者号”“密码”的输入框,输入读者姓名
    Label(second_frame,text = "登录界面",font = ("黑体",20),width = 20,height = 3).place(x=300, y=20)
    Label(second_frame,text = "读者号:",font = ("黑体",18),width = 20,height = 3).place(x=100, y=100)
    Label(second_frame,text = "密码:",font = ("黑体",18),width = 20,height = 3).place(x=100, y=175)
    num_entry = Entry(second_frame,show = None, font=("黑体", 18), width=25)  #姓名输入框
    num_entry.place(x = 300,y = 135)
    password_entry = Entry(second_frame,show = '*', font=("黑体", 18), width=25)  #姓名输入框
    password_entry.place(x = 300,y = 200)
    #设置“确认”按钮,跳转到get_value()函数:该函数功能将读者与读者编号填下到第一个表格中
    Button(second_frame,text = "确认",bg = "SkyBlue",font = ("黑体",12),width = 15,height = 3,command = lambda:functions(second_frame,num_entry,password_entry)).place(x= 180,y = 300)
    Button(second_frame,text = "返回",bg = "SkyBlue",font = ("黑体",12),width = 15,height = 3,command = lambda:back_main(second_frame,main_frame)).place(x= 550,y = 300)

登录界面的效果如下图:
在这里插入图片描述

  1. 服务功能界面functions函数
    在登录界面点击“确认”按钮后,跳转到服务功能界面,是新的界面,同样要布局新的框架,隐藏就框架(下面不在赘述)。程序中首先利用get()方法获取输入的读者号和读者密码,用于验证。验证的时候需要利用之前就已经加载好的表格,遍历获取表格中的第一列和第二列内容,确认读者身份,验证成功通过设置的标志位pass_flag为1,跳出循环。最后在根据验证标志位弹出服务功能界面,该界面放置了借书、还书、查询、退出系统的4个功能按钮,同时还显示读者的姓名。假如读者输入错误,则会弹出弹窗,报警提示输入错误,并返回登录界面,让读者重新输入账号、账号密码。
#功能界面:借书、还书、查询、退出系统功能
def functions(second_frame,num_entry,password_entry):
    num = num_entry.get()  #get()方法获取Entry输入框输入内容
    password = password_entry.get() 
    print(num,password,type(num))
    #隐藏第一个界面,设置第二个界面
    second_frame.place_forget()
    third_frame = Frame(top)
    third_frame.place(relwidth=1,relheight=1)  
    pass_flag = 0  #验证标志位
    for i in range(2,max_row1+1):   #遍历表格
        #验证读者号和密码是否正确。读者号在第一列,密码在第三列
        if num == str(sheet1.cell(i,1).value) and password == str(sheet1.cell(i,3).value):
            pass_flag = 1  #验证标志位为1
            break #跳出循环          
        else: #密码或账号出错
            pass_flag = 0  #验证标志位为0
    if pass_flag == 1:  #判断验证标志位
        #服务功能按钮
        print("验证成功")
        Label(third_frame,text = str(sheet1.cell(i,2).value) + ",欢迎您",font = ("黑体",40),width = 30,height = 3).place(x=10,y = 0)
        Button(third_frame,text = "借书",bg = "SkyBlue",command = lambda:Borrow_books(third_frame,num),font = ("黑体",12),width = 15,height = 3).place(x= 150,y = 200)
        Button(third_frame,text = "还书",bg = "SkyBlue",command = lambda:ruturn_books(third_frame,num),font = ("黑体",12),width = 15,height = 3).place(x= 550,y = 200)
        Button(third_frame,text = "查询",bg = "SkyBlue",command = lambda:Inquire(third_frame,num) ,font = ("黑体",12),width = 15,height = 3).place(x= 150,y = 350)
        Button(third_frame,text = "退出",bg = "SkyBlue",font = ("黑体",12),width = 15,height = 3,command=lambda:back_main(third_frame,main_frame)).place(x= 550,y = 350)  
    else:
        messagebox.showinfo('警告!', '密码或账号出错!')  #弹出警告窗口
        back_main(third_frame,second_frame) #账号密码出错则返回登录界面  

登录成功后,服务界面如图所示:
在这里插入图片描述

  1. “借书”按钮Borrow_books函数
    在服务界面点击“借书”按钮后,跳转到Borrow_books函数。该界面是新的界面,放置了6种不同种类的书籍按钮,分别是“文学”、“计算机”、“历史”、“法律”、“心理学”、“医学”,每一个按钮按下去都会进入对应种类书籍的名称·,注意按钮中command参数链接的函数BOOK函数,传递的参数中最后一个参数是书籍的分类,也就是下面classify,是之前提到的全部书籍字典book_sum中对应的“键“。
#借书按钮
def Borrow_books(third_frame,num):
    #隐藏第一个界面,设置第二个界面
    third_frame.place_forget()
    fourth_frame = Frame(top)
    fourth_frame.place(relwidth=1,relheight=1)  
    Label(fourth_frame,text = "图书分类",font = ("黑体",40),width = 30,height = 3).place(x=10,y = 0)
    Button(fourth_frame,text = "文学",bg = "white",command = lambda:BOOK(fourth_frame,num,"文学"),font = ("黑体",12),width = 15,height = 3).place(x= 150,y = 200)
    Button(fourth_frame,text = "计算机",bg = "white",command = lambda:BOOK(fourth_frame,num,"计算机"),font = ("黑体",12),width = 15,height = 3).place(x= 350,y = 200)
    Button(fourth_frame,text = "历史",bg = "white",command = lambda:BOOK(fourth_frame,num,"历史"),font = ("黑体",12),width = 15,height = 3).place(x= 550,y = 200)
    Button(fourth_frame,text = "法律",bg = "white",command = lambda:BOOK(fourth_frame,num,"法律"),font = ("黑体",12),width = 15,height = 3).place(x= 150,y = 350)
    Button(fourth_frame,text = "心理学",bg = "white",command = lambda:BOOK(fourth_frame,num,"心理学"),font = ("黑体",12),width = 15,height = 3).place(x= 350,y = 350)
    Button(fourth_frame,text = "医学",bg = "white",command = lambda:BOOK(fourth_frame,num,"医学"),font = ("黑体",12),width = 15,height = 3).place(x= 550,y = 350)  

借书界面效果如图:
在这里插入图片描述

  1. 书籍选择界面
    以“计算机”类书籍为例,按“计算机”按钮后,界面会呈现关于计算机书籍的基本书籍名称,通过按下书籍前面对应的小方块,然后按下确认按钮可以确认书籍的选择。这部分主要是书籍列表复选框的设计,可以利用tkinter中的Checkbutton复选框组件,参数text是复选框旁边的文字,也就是书籍的名称,通过嵌套字典来获得book_sum[classify][i],variable参数设置或取得目前选取的复选框。确认按钮关联selection函数,传递了读者号num、选择的书籍checkboxes、书籍类别classify等参数
#选择小说类书籍:设计复选框,可进行多本书籍选择
def BOOK(fourth_frame,num,classify):
    print("classify:",classify)
    print("指定书籍",book_sum["法律"])
    #隐藏第一个界面,设置第二个界面
    fourth_frame.place_forget()
    fifth_frame = Frame(top)
    fifth_frame.place(relwidth=1,relheight=1)  
    Label(fifth_frame,text="选择你想要借的书籍",font = ("黑体",20),fg="blue",bg="lightyellow",width=60).grid()
    checkboxes = {}
    for i in range (8):
        checkboxes[i] = BooleanVar()
        Checkbutton(fifth_frame,text=book_sum[classify][i],variable=checkboxes[i],font = ("黑体",15),height = 1).grid(row = i+1,sticky = W)  #列表逐个显示书籍
    Button(fifth_frame,text="确定",bg = "SkyBlue",font = ("黑体",12),width = 15,height = 3,command=lambda:selection(fifth_frame,num,checkboxes,classify)).place(x = 180, y =400)       
    Button(fifth_frame,text="取消",bg = "SkyBlue",font = ("黑体",12),width = 15,height = 3,command=lambda:back_main(fifth_frame,main_frame)).place(x = 550, y =400)   

选择界面效果如图
在这里插入图片描述

  1. 确认书籍选择selection函数
    当上一界面点击“确认”按钮,确认了选择借阅的书籍之后,跳转到selection函数,将书籍登记到表格中。定义列表list1来存放选中的复选框内容,利用get()方法获取复选框是否被勾选,方法checkboxes[i].get(),如果第几个被勾选了,那么结果为Ture,将复选框的内容book_sum[classify][i]添加到列表中。在弹出的“是否确认借阅”弹窗中,点击“确认”,借阅即记录将会以字符串形式保存到表格中,如“三国演义 水浒传 西游记 红楼梦”。可见效果图。
#确认选择的书籍,将书籍登记到借阅记录
def selection(fifth_frame,num,checkboxes,classify):
    list1 = []  #定义空列表,用来存放选择借阅的书籍
    for i in checkboxes:
        if checkboxes[i].get() == True:  #判断哪一项是否被选          
            list1.append(book_sum[classify][i]) #将被选项组成列表 
    confirm = messagebox.askokcancel('提示!','是否确认借阅?')
    if confirm == True:  #弹出提示借阅的窗口
        for i in range(2,max_row1+1):
            if sheet1.cell(i,1).value == int(num):
                print(sheet1.cell(i,2).value+"借书")
                #将读者选择的几本书以字符串形式,空格为间隔保存到表格中,例如 “三国演义 水浒传 西游记 红楼梦”,方法如下
                sheet1.cell(i,4).value = ' '.join(list1)   #将借阅书籍列表中的各个字符串元素重新组合成一个新的字符串,中间是空格 
                sheets.save(path + "Data.xlsx")   #保存表格
        messagebox.showinfo("提示!",'借阅成功,返回主界面!')
        back_main(fifth_frame,main_frame)

保存到表格中的借阅记录如图所示:
在这里插入图片描述

  1. “还书”按钮ruturn_books函数
    在服务界面点击“还书”按钮后,跳转到ruturn_books函数。在新的还书界面中,放置了需要归还“图书名称“的文本输入框,”确认借阅“按钮链接了data_val函数,该函数对表格中的借阅记录进行操作。”返回上级“按钮直接跳转到主界面。
#还书按钮
def ruturn_books(third_frame,num):
    #隐藏旧界面,设置新界面
    third_frame.place_forget()
    fourth_frame = Frame(top)
    fourth_frame.place(relwidth=1,relheight=1)
    Label(fourth_frame,text = "还书服务界面",font = ("黑体",20),width = 20,height = 3).place(x=300, y=20) 
    Label(fourth_frame,text = "图书名称:",font = ("黑体",20),width = 20,height = 3).place(x=100, y=100)    
    Label(fourth_frame,text = "备注:请输入归还书籍的名称,比如朝花夕拾,每次仅输入一本哦~",font = ("楷体",12),width = 100,height = 2).place(x=30, y=180) 
    book_entry = Entry(fourth_frame, font=("黑体", 20), width=20)  #书本输入框
    book_entry.place(x = 350,y = 130)
    #设置“确认”按钮,跳转到get_value()函数:该函数功能将读者与读者编号填下到第一个表格中
    Button(fourth_frame,text = "确认归还",bg = "SkyBlue",font = ("黑体",12),width = 15,height = 3,command = lambda:data_val(num,book_entry)).place(x= 180,y = 300)
    Button(fourth_frame,text = "返回上级",bg = "SkyBlue",font = ("黑体",12),width = 15,height = 3,command = lambda:back_main(fourth_frame,main_frame)).place(x= 550,y = 300)

还书界面效果如下图:
在这里插入图片描述

  1. 修改表格中还书数据data_val函数
    点击还书界面中的“确认归还“按钮后,跳转到data_val函数。该函数需要将读者要归还的图书从借阅记录表格中删减。因此函数传递的参数是读者号和读者要归还的图书名称,通过读者号num遍历表格,定位到读者在表格中的位置i,在第几行,获取读者的借阅记录sheet1.cell(i,4).value (第i行中的第4列),然后通过split()方法指定分隔符对字符串进行切片.括号内为空,即字符串按空格分割成列表,转化成列表,遍历列表,找到和读者输入一摸一样的书名,然后利用remove()方法,删减列表中该书记录。删除后,同样利用’ '.join(book_list)方法,把删除后新的列表以字符串形式赋值到读者的借阅记录中,若读者输入错误,则出现弹出提示。
#修改表格中还书数据
def data_val(num,book_entry):
    borrowing_records = '' #定义读者的借阅记录
    confirm = messagebox.askokcancel('提示!','是否确认归还?')
    if confirm == True:  #弹出提示借归还的窗口
        book = book_entry.get()  #获取读者输入的图书名称
        for i in range(2,max_row1+1):
            if num == str(sheet1.cell(i,1).value) :
                reader_flag = 1 #标记位
                break   #定位读者在表格中的位置i,第几行
            else:
                reader_flag = 0  #标记位
        if reader_flag == 1:
            borrowing_records = str(sheet1.cell(i,4).value)  #获取表格中读者的借阅记录
            book_list = borrowing_records.split()  #split()方法通过指定分隔符对字符串进行切片.括号内为空,即字符串按空格分割成列表,转化成列表
            return_flag = 0 
            for k in book_list:  #遍历列表
                if k ==  str(book):  #找到读者要还的书
                    return_flag = 1  #成功找到这本书的标志位
                    print("找到")
                    break #找到就跳出
                else:
                    return_flag = 0  #没有找到,或者输入有误,需要提示
            if return_flag == 1:
                book_list.remove(k)  #删除列表中这本书的记录
                sheet1.cell(i,4).value = ' '.join(book_list)  #将删除后的记录重新赋值到读者的借阅记录中
                print(str(book_list))
                sheets.save(path + "Data.xlsx")  #操作表格后要记得保存数据哦  
                messagebox.showinfo("提示!",'还书成功!')
            else:
                messagebox.showinfo("提示!",'输入有误,请重新输入!')

确认还书操作效果如图
在这里插入图片描述

  1. 查询按钮Inquire函数
    在服务界面点击“查询”按钮后,跳转到Inquire函数。通过传递的参数num(读者号)获取读者在“Data.xlsx“表格中的借阅记录、读者姓名,然后将读者姓名和借阅记录显示在界面上。注意,由于借阅记录蛮长的,这里借助Label组件中的wraplength参数,该参数决定 Label 的文本应该被分成多少行,该选项指定每行的长度,单位是屏幕单元,这里可能需要慢慢调试看看,高度也需要设置大一些。
#查询按钮函数
def Inquire(third_frame,num):
    #隐藏旧界面,设置新界面
    third_frame.place_forget()
    fourth_frame = Frame(top)
    fourth_frame.place(relwidth=1,relheight=1)
    for i in range(2,max_row1+1):  #遍历表格,通过输入的编号,#定位读者在表格中的位置i,第几行
        if num == str(sheet1.cell(i,1).value) :
            reader_flag = 1 #标记位
            break   
        else:
            reader_flag = 0  #标记位
    if reader_flag == 1:
       name = sheet1.cell(i,2).value  #通过读者在表格中的行数,获取这名读者的名字
       borrowing_records = sheet1.cell(i,4).value #通过读者在表格中的行数,获取这名读者的借阅记录
    Label(fourth_frame,text = "查询服务界面",font = ("黑体",25),width = 50,height = 2).place(x=0, y=0) 
    Label(fourth_frame,text = "读者: " ,font = ("黑体",20),width = 15,height = 3).place(x=20, y=100)   #“读者”文字标签
    Label(fourth_frame,text = name ,font = ("黑体",20),fg = 'red',width =40,height = 3).place(x=200, y=100)   #读者姓名
    Label(fourth_frame,text = "借阅书籍: ",font = ("黑体",20),width = 15,height = 3).place(x=20, y=200)    #“借阅书籍”文字标签
    Label(fourth_frame,text =  borrowing_records, wraplength=350, font = ("黑体",20),fg = 'red',width = 40,height = 5).place(x=200, y=200)   #"借阅书籍"记录,wraplength这个参数让文字达到200像素后自动换行
    Button(fourth_frame,text = "返回上级",bg = "SkyBlue",font = ("黑体",20),width = 20,height =2,command=lambda:back_main(fourth_frame,main_frame)).place(x= 300,y = 400)

查询界面效果如下:
在这里插入图片描述

  1. 返回按钮函数,从a界面调转到main_frame框架组件布置的界面,比较简单不细讲。
#返回按钮函数
def back_main(a,main_frame):
    a.place_forget() 
    top.geometry("800x500")
    main_frame.place(relwidth=1,relheight= 1)

五、备注

①第1部分主界面的程序放在所以定义的函数后面,path路经需要根据实际情况修改,
②完整程序和表格链接
链接:点我:完整程序和Data.xlsx表格
提取码:lyx4