python+tkinter实现图书管理系统(首发)

文章目录

  • 前文
  • 运行环境
  • 功能图
  • 数据操作
    • 图书数据管理
    • 用户数据管理
    • 借书记录管理
  • 功能界面
    • 管理员界面
      • 首页
      • 图书管理
      • 用户管理
      • 借书记录
      • 更改密码
    • 普通用户界面
  • 其他功能
    • 数字时间显示
    • 加载画面显示
    • 输入框提示词
    • 界面居中显示
    • 借书时间和还书时间记录
    • 公告栏数据操作
  • 结尾

前文

本文将用tkinter模块来写一个图书管理系统,将用户分为管理员和普通用户,用户都有首页,首页展示天气预报并有公告栏。管理员有权限对用户、图书进行添加、修改、删除等操作。普通用户只有搜索图书的功能。本文几乎涉tkinter的所有组件,适合新手练习tkinter,欢迎大家的订阅。

运行环境

编译器:PyCharm 2021.2.1
解释器:Anaconda 3.8
pip install opencv-python==4.5.5.64
温馨提示,最好是在本文所要求环境运行,避免程序可能出现报错。

功能图

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

数据操作

数据操作是对数据进行操作,如增删改查,用户在界面上的操作实际就是对数据的操作,只不过用户看到的是界面,只需点点就行了,操作更方便,更容易,因为我们都把功能写好了。

图书数据管理

Book类有7个方法,分别为query_book()、add_book()、del_book()、 mod_book()、write_book()、read_book(),first_add_book()。
query_book()为查询图书,我们只需要把书的id、书名或者作者作为搜索条件,将返回列表,如果没有数据则返回空列表。 首先我们先获取所有列表的索引,然后根据字典取值,判断他们是否相等,如果相等则添加到列表中,否则就不添加。
add_book(),添加图书,首先调用query_book()函数,传入id,判断图书是否在书库里,如果存在返回False,不存在返回True,表示可以添加。
del_book(),根据传入的书名,查找图书,找到了就删除,没有则不作为。
mod_book(),修改图书,和add_book()类似,也是先查找,找到图书,根据传入的参数,对图书进行修改。
write_book(),写入文件,将self.books写入文件并保存到本地。
read_book(),读取所有的图书。
first_add_book(),第一次运行没有图书,将自动添加图书并创建文件夹保存,数据格式为json。

import json
import os'''
数据格式
[{
'id':'', 'title':'', 'author':'', 'classify':'', 'inventory':'', 'content':'' }]
'''class Book:def __init__(self):self.first_add_book()self.read_book()# 查询def query_book(self, search):all_book_list = []for i in range(0, len(self.books)):for v in ['id', 'title', 'author']:# 也可用 findif str(search) == self.books[i][v]:print('找到了', self.books[i])all_book_list.append(self.books[i])return all_book_list# 添加def add_book(self, id, title, author, classify, inventory, content):# 是否已经存入if not self.query_book(id):# 可以增加防重复的new_book = {}new_book['id'] = idnew_book['title'] = titlenew_book['author'] = authornew_book['classify'] = classifynew_book['inventory'] = inventorynew_book['content'] = contentself.books.append(new_book)print('添加', new_book)self.write_book()return Trueelse:return False# 删除def del_book(self, book_name):result = self.query_book(book_name)if result:self.books.remove(result[0])print('删除', result)self.write_book()# 修改def mod_book(self, old_id, id, title, author, classify, inventory, content):result = self.query_book(old_id)if result:result[0]['id'] = idresult[0]['title'] = titleresult[0]['author'] = authorresult[0]['classify'] = classifyresult[0]['inventory'] = inventoryresult[0]['content'] = contentself.write_book()return Truereturn Falsedef write_book(self):with open('book_info.json', mode='w', encoding='utf-8') as f:f.write(json.dumps(self.books))def read_book(self):with open(r'book_info.json', mode='r', encoding='utf-8') as r:self.books = json.loads(r.read())print('读取的数据', self.books)return self.booksdef first_add_book(self):self.books = []name = 'book_info.json'if not (name in os.listdir()):print('开始初次写入用户信息')with open(r'book_info.json', mode='w', encoding='utf-8') as f:id_num = ['123', '133', '456', '213']title = ['西游记', '红楼梦', '三国演义', '水浒传']author = ['吴承恩', '曹雪芹', '罗贯中', '施耐庵']classify = ['小说', '小说', '小说', '小说']inventory = ['1', '10', '20', '5']content = ['唐僧、孙悟空、猪八戒、沙僧、白龙马,西天取经,历经九九八十一难, 终于取到真经的故事','《红楼梦》以贾宝玉、林黛玉、薛宝钗之间的恋爱婚姻悲剧为主线,描写了以贾家为代表的四大家族的兴衰,揭示了封建大家庭的各种错综复杂的矛盾','三国演义以描写战争为主,反映了蜀、魏、吴三个政治集团之间的政治和军事斗争。','全书通过描写梁山好汉反抗欺压、水泊梁山壮大和受宋朝招安,以及受招安后为宋朝征战,最终消亡的宏大故事,艺术地反映了中国历史上宋江起义从发生、发展直至失败的全过程,深刻揭示了起义的社会根源,满腔热情地歌颂了起义英雄的反抗斗争和他们的社会理想,也具体揭示了起义失败的内在历史原因。']for i in range(4):data = {}data['id'] = id_num[i]data['title'] = title[i]data['author'] = author[i]data['classify'] = classify[i]data['inventory'] = inventory[i]data['content'] = content[i]self.books.append(data)f.write(json.dumps(self.books, ensure_ascii=False))print('初次写入完毕', self.books)if __name__ == '__main__':book = Book()# book.query_book('123')# book.query_book('西游记')# book.query_book('水浒传')# book.del_book('西游记')a = {'id': '123', 'title': '西游记', 'author': '吴承恩', 'classify': '小说', 'inventory': '1','content': '唐僧、孙悟空、猪八戒、沙僧、白龙马,西天取经,历经九九八十一难, 终于取到真经的故事'}## book.add_book(*a)book.mod_book('133', *a)

用户数据管理

用户数据管理和图书数据管理类似,这里就不作过多的讲解。看代码。

import json
import os'''
[{user:'', password:'', state:''},{},][[], []] 学生用户 管理员用户
全部默认字符串
{'user':[{}], 'admin':[{}]}
1 普通用户
2 管理员用户名唯一
'''#  用户信息用字典来操作 包括增删改查功能的实现class UserOperation:def __init__(self, flag):self.flag = flagself.user_first_add()self.read_user()def user_add(self, user, password, state=0):# 首先判断有没有重复的result = self.user_query(user)if not result:if self.flag == 1:self.user_info['stu'].append({'user': str(user), 'password': str(password), 'state': str(state)})self.write_user()return Trueif self.flag == 2:self.user_info['admin'].append({'user': str(user), 'password': str(password)})self.write_user()return Trueelse:print('已经有了')def user_modify(self, user, old_password, new_password, state=0):result = self.user_query(user)if result:if result['password'] == old_password:if self.flag == 1:for i in self.user_info['stu']:if result['user'] == i['user']:i['user'] = useri['password'] = new_passwordi['state'] = str(state)self.write_user()return Trueif self.flag == 2:for i in self.user_info['admin']:if result['user'] == i['user']:i['user'] = useri['password'] = new_passwordself.write_user()return Truedef user_del(self, user):result = self.user_query(user)if result:for i in self.user_info['stu']:if result['user'] == i['user']:self.user_info['stu'].remove(i)print('删除成功')self.write_user()return Truedef user_query(self, user):if self.flag == 1:for i in self.user_info['stu']:if user == i['user']:print('查找成功!')return ielse:return Noneif self.flag == 2:for i in self.user_info['admin']:if user == i['user']:print('查找成功!')return ielse:return None# 读取所有数据def read_user(self):with open(r'user.json', mode='r', encoding='utf-8') as r:self.user_info = json.loads(r.read())print('读取的数据', self.user_info)# 用于写入数据def write_user(self):with open(r'user.json', mode='w', encoding='utf-8') as w:w.write(json.dumps(self.user_info))print('写入的数据', self.user_info)def user_first_add(self):name = 'user.json'if not (name in os.listdir()):print('开始初次写入用户信息')with open(r'user.json', mode='w', encoding='utf-8') as f:data = {}data['stu'] = []data['stu'].extend([{'user': '123456', 'password': '123456', 'state': '0'},{'user': '123', 'password': '123', 'state': '0'}])data['admin'] = []data['admin'].append({'user': 'admin', 'password': 'admin'})f.write(json.dumps(data))print('初次写入完毕', data)if __name__ == '__main__':user_active = UserOperation(1)print(user_active.user_query('123'))# user_active.user_del('admin')# user_active.user_add('1234', '1234')# user_active.user_modify('123', '12345', '0')

借书记录管理

Record类主要函数是estimate_upper_limit(),用于判断用户的借书数量,当借书数量大于或者等于2时,就返回True,不允许用户再借书了。其余方法与上文相似,看代码。

import os
import jsondef first_run():name = 'record.json'if not (name in os.listdir()):print('开始初次写入用户信息')with open(r'record.json', mode='w', encoding='utf-8') as f:f.write(json.dumps([]))class Record:def __init__(self):first_run()self.read_record()def read_record(self):with open(r'record.json', mode='r', encoding='utf-8') as f:self.record_books = json.loads(f.read())def write_record(self):with open(r'record.json', mode='w', encoding='utf-8') as f:f.write(json.dumps(self.record_books))print('写入记录成功', self.record_books)# 借书上限为2def estimate_upper_limit(self, user):borrow_books = []for book in self.record_books:if book['user'] == user:if int(book['book_num']) > 1:return Trueelse:borrow_books.append(book)if len(borrow_books) >= 2:return Truereturn False# 还书def drop_book(self, book_id, user):all_books = []for book in self.record_books:if book['id'] == book_id and book['user'] == user:all_books.append(book)if all_books:return all_booksreturn False# 查询用户def query_user(self, user):dance = []for o in self.record_books:if o['user'] == user:dance.append(o)print(dance)return danceif __name__ == '__main__':record = Record()record.write_record()

功能界面

登录界面核心功能check_login()函数用于检查登录是否成功,检查是否存在此用户,密码错误超过了三次账号就会被封禁,需要联系管理员解封。管理员登录则宽松许多,可以一直登录,直到登录成功。

import tkinter
import tkinter.messagebox
from tkinter_book.operation_data.user_operation import UserOperation
import tkinter.ttk
from tkinter_book.other_fun.gui_loading import Loading
from tkinter_book.other_fun.center_gui import gui_centerclass Login(tkinter.Tk):def __init__(self):super(Login, self).__init__()self.title('登录')self.resizable()  # 不允许更改窗口# style = tkinter.ttk.Style()# print(style.theme_names())# style.theme_use('xpnative')gui_center(self, 500, 420)self.all_info = UserOperation(1)self.all_info_2 = UserOperation(2)self.num = 0self.flag = Falseself.shou_wel()self.gui_login()self.mainloop()def shou_wel(self):font_frame = tkinter.Frame(self, width=400, height=50)book_manage = tkinter.Label(font_frame, text='欢迎登录图书管理系统', font=("Arial", 24), foreground='red')book_manage.place(relx=0.05, rely=0.05)font_frame.place(relx=0.15, rely=0.05)def gui_login(self):user_frame = tkinter.Frame(self, width=400, height=300)self.v_user = tkinter.StringVar()self.v_password = tkinter.StringVar()self.vali = tkinter.IntVar()self.vali.set(1)self.text_user = tkinter.Label(user_frame, text='用户名', font=("Arial", 19))self.entry_user = tkinter.Entry(user_frame, width=15, textvariable=self.v_user, font=("Arial", 19))self.text_password = tkinter.Label(user_frame, text='密   码', font=("Arial", 19))self.entry_password = tkinter.Entry(user_frame, width=15, textvariable=self.v_password, font=("Arial", 19),show='*')self.button_login = tkinter.Button(user_frame, text='登录', fg='red', font=("Arial", 20),command=self.check_login)self.radio1 = tkinter.Radiobutton(user_frame, variable=self.vali, value=1, text='学生登录', font=("Arial", 9))self.radio2 = tkinter.Radiobutton(user_frame, variable=self.vali, value=2, text='管理员登录', font=("Arial", 9))self.text_user.place(relx=0.1, rely=0.1)self.entry_user.place(relx=0.32, rely=0.1)self.text_password.place(relx=0.1, rely=0.25)self.entry_password.place(relx=0.32, rely=0.25)self.button_login.place(relx=0.4, rely=0.42)self.radio1.place(relx=0.3, rely=0.65)self.radio2.place(relx=0.3, rely=0.75)user_frame.place(relx=0.1, rely=0.2)self.show_text = tkinter.Label(self, text='C站关注天天501', font=('Arial', 9))self.show_text.place(relx=0.8, rely=0.95)def check_login(self):# print(self.vali.get())# 学生登录if int(self.vali.get()) == 1:e_get_u = self.entry_user.get()e_get_p = self.entry_password.get()result = self.all_info.user_query(e_get_u)#  print(result)if not result:tkinter.messagebox.showerror('错误提醒', '此账号不存在!')returnif result['state'] != '0':tkinter.messagebox.showerror('提醒', '此账号已经封禁,请联系管理员')returnif e_get_u == result['user'] and e_get_p == result['password']:self.destroy()Loading()# print('登录成功!')self.flag = Trueelif e_get_u == result['user'] and e_get_p != result['password']:self.num += 1if self.num >= 3:print('错误提醒', '账号锁定,请联系管理员!')self.num = 0result['state'] = '1'self.all_info.write_user()tkinter.messagebox.showerror('错误提醒', '此账号已经封禁,请联系管理员')returntkinter.messagebox.showerror('错误提醒', f'密码错误,你还有{str(3 - self.num)}机会')else:tkinter.messagebox.showerror('错误提醒', '账号或密码错误!')# 学生登录if int(self.vali.get()) == 2:e_get_u = self.entry_user.get()e_get_p = self.entry_password.get()result = self.all_info_2.user_query(e_get_u)print(result)if not result:tkinter.messagebox.showerror('错误提醒', '此账号不存在!')returnif e_get_u == result['user'] and e_get_p == result['password']:self.destroy()Loading()print('登录成功!')self.flag = Truereturn 2elif e_get_u == result['user'] and e_get_p != result['password']:tkinter.messagebox.showerror('错误提醒', '密码错误')else:tkinter.messagebox.showerror('错误提醒', '账号或密码错误!')if __name__ == '__main__':Login()

管理员界面

首页

首页的天气预报需要爬取数据,我们选择爬2345的,分为两部分,第一部分,将天气图片爬下来,用类名存储图片。第二部分爬取城市天气数据用列表存储,且支持搜索城市天气。这爬虫比较简单,而且网站也没有什么反爬,正常流程走就行了。下面展示部分代码。

# https://tianqi.2345.com/ 爬天气预报
import os
import urllib.parse
import requests
import parsel
from tkinter_book.background_url import update_pictdef search_city(name='北京'):# 定义字典data = {'city': '', 'teacher': []}# 获取所有目录 图片缩放all_img_file = update_pict()# 转化为url编码name_ = urllib.parse.quote(name)url_1 = f'https://tianqi.2345.com/tpc/searchCity.php?q={name_}&pType=pc'headers = {'Referer': 'https://tianqi.2345.com/','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'}# 搜索 没有搜索到会返回空值search = requests.get(url=url_1, headers=headers)response_city = search.json()['res']if response_city:url = 'https://tianqi.2345.com' + response_city[0]['href']response = requests.get(url=url, headers=headers)html_data = parsel.Selector(response.text)city = html_data.css('.banner-city-change span::text').get()tea_all = html_data.css('#J_bannerList .banner-right-con-list-item')data['city'] = cityfor i in tea_all:week = i.css('.banner-right-con-list-time::text').get().strip()date = i.css('.date::text').get().strip()img = i.css('.banner-right-con-list-icon::attr(class)').get().strip().split(' ')[-1] + '.png'# 给图片设置路径if img in all_img_file:img = 'imgs//' + imgelse:img = 'imgs//' + 'wea-rc.png'  wea = i.css('.banner-right-con-list-status::text').get().strip()tem = i.css('.banner-right-con-list-temp::text').get().strip()data['teacher'].append([week, date, img, wea, tem])return dataelse:print('搜索无效')data['city'] = 'None'for i in range(8):data['teacher'].append(['None', 'None', 'None', 'None', 'None'])return dataif __name__ == '__main__':print(search_city())

既然数据已经爬取完了,那接下来就是将数据展现出来,这里用到了grid布局,类似于表格,方便咱们排列。下面看代码。

import tkinter.ttk
import tkinter
from tkinter_book.get_weather import search_city
from tkinter_book.other_fun.tip_entry import NewEntry
from tkinter_book.other_fun.announcement_data import announcement_write, announcement_read, first_write
import tkinter.messageboxclass HomePage:def __init__(self, flag):self.weather_lists = []self.flag = flagself.get_city_weather()self.gui_home()self.update_weather()self.set_text()def gui_home(self):self.home_frame = tkinter.Frame()# 选项卡容器self.home_frame.pack()self.search_frame = tkinter.Frame(self.home_frame)self.weather_frame = tkinter.Frame(self.home_frame)self.search_frame.pack()self.weather_frame.pack()# 公告栏self.notice_label = tkinter.LabelFrame(self.home_frame, text='公告栏', width=700, height=200)# 不随子件变化self.notice_label.pack_propagate(0)self.notice_label.pack(pady=30)def update_weather(self):self.weather_lists.clear() # 清空列表self.entry = NewEntry(self.search_frame, '请输入搜索城市')button = tkinter.Button(self.search_frame, text='搜索', command=self.search_button)show_city = tkinter.Label(self.search_frame, text=self.data['city'], font=('宋体', 24))show_city.pack(side='left', padx=10, pady=10)self.entry.pack(side='left', padx=10, pady=10)button.pack(side='left', padx=5, pady=10)# 列不变for column in range(1, 6):# 获取每一行的值for row in range(1, 9):if column != 3:tkinter.Label(self.weather_frame, text=self.data['teacher'][row - 1][column - 1]).grid(row=column,column=row - 1,padx=15,pady=9)else:try:self.weather_lists.append(tkinter.PhotoImage(file=self.data['teacher'][row - 1][column - 1]))tkinter.Label(self.weather_frame, image=self.weather_lists[row - 1]).grid(row=column,column=row - 1,padx=15,pady=9)except:tkinter.Label(self.weather_frame, text='无图').grid(row=column,column=row - 1,padx=15,pady=9)def get_city_weather(self, city='北京'):try:self.data = search_city(city)except:self.data = {'city': 'None', 'teacher': []}for i in range(8):self.data['teacher'].append(['None', 'None', 'None', 'None', 'None'])def search_button(self):v = self.entry.get_input_box()self.get_city_weather(v)print(self.data)# 删除搜索里的组件for item in self.search_frame.winfo_children():item.destroy()# 天气里的组件for item in self.weather_frame.winfo_children():item.destroy()self.update_weather()# 还要加按钮 设置文本def set_text(self):if self.flag == 1:first_write()self.text = tkinter.Text(self.notice_label)self.text.insert(tkinter.INSERT, announcement_read())self.text.configure(state='disabled')self.text.pack(fill=tkinter.BOTH, expand='true')if self.flag == 2:first_write()self.text = tkinter.Text(self.notice_label)self.text.insert(tkinter.INSERT, announcement_read())self.text.pack(fill=tkinter.BOTH, expand='true')# 提交按钮text_submit = tkinter.Button(self.home_frame, text='提交', width=6, command=self.button_text)# self.text.window_create('1.9', window=text_submit)text_submit.pack()def button_text(self):r = self.text.get('1.0', tkinter.END)announcement_write(txt=r)tkinter.messagebox.showinfo('提醒', '保存成功!', parent=self.home_frame)if __name__ == '__main__':root = tkinter.Tk()style = tkinter.ttk.Style()note = tkinter.ttk.Notebook(root)home = HomePage(1)style.configure('TNotebook.Tab', font=("微软雅黑", 20, 'bold'), foreground='red')root.geometry('800x600+450+150')note.add(home.home_frame, text='首页')note.pack(fill='both', expand='true')root.mainloop()

图书管理

我们将图书管理分为两部分,左边为为功能区,右边为图书显示区。左边为添加、修改、借书、还书、删除。功能已经写好了,我们只需要把界面写出来就行了,右边也是一样的。

import tkinter
from tkinter_book.other_fun.tip_entry import NewEntry
import tkinter.ttk
import tkinter.messagebox
from tkinter_book.other_fun.center_gui import gui_center
from tkinter_book.operation_data.user_operation import UserOperation
from tkinter_book.operation_data.record_book import Record
from tkinter_book.operation_data.book_operation import Book
from tkinter_book.other_fun.write_time import ComputingTime'''对图书进行增删改查、图书的借还
添加   搜索
删除  show
修改
借书
还书
'''class Admin:def __init__(self):self.book = Book()self.show_book()# 展示界面def show_book(self):self.main_show_frame = tkinter.Frame()about_frame = tkinter.LabelFrame(self.main_show_frame, width=160, height=500, text='功能区')show_book_frame = tkinter.Frame(self.main_show_frame, width=800, height=700)self.tree = tkinter.ttk.Treeview(show_book_frame, columns=('id', 'title', 'author', "classify", "inventory"),show='headings', height=20, selectmode='browse')self.tree.heading('id', text='id', anchor='center')self.tree.heading('title', text='书名', anchor='center')self.tree.heading('author', text='作者', anchor='center')self.tree.heading('classify', text='分类', anchor='center')self.tree.heading('inventory', text='库存', anchor='center')self.tree.column('id', anchor='center', width=80)self.tree.column('title', anchor='center', width=160)self.tree.column('author', anchor='center', width=120)self.tree.column('classify', anchor='center', width=90)self.tree.column('inventory', anchor='center', width=80)for i in self.book.read_book():self.tree.insert('', tkinter.END, values=(i['id'], i['title'], i['author'], i['classify'], i['inventory']))# 搜索框+按钮self.search_entry = NewEntry(show_book_frame, '请输入id或者作者')self.search_button = tkinter.Button(show_book_frame, text='搜索', command=self.search_v)self.update_button = tkinter.Button(show_book_frame, text='刷新', command=self.update_books)self.search_entry.place(relx=0.3, rely=0.05)self.search_button.place(relx=0.5, rely=0.04)self.update_button.place(relx=0.55, rely=0.04)self.tree.place(relx=0.05, rely=0.1)show_book_frame.place(relx=0.25, rely=0.01)# 按钮样式button_style = tkinter.ttk.Style()button_style.configure('TButton', font=("微软雅黑", 18, 'bold'), foreground='grey', width=8)# 添加add_button = tkinter.ttk.Button(about_frame, text='添加', style='TButton', command=lambda: self.show_toplevel(1))add_button.pack(pady=20)# 修改mod_button = tkinter.ttk.Button(about_frame, text='修改', style='TButton', command=lambda: self.show_toplevel(2))mod_button.pack(pady=20)# 借书lend_button = tkinter.ttk.Button(about_frame, text='借书', style='TButton',command=lambda: self.borrow_toplevel())lend_button.pack(pady=20)# 还书even_button = tkinter.ttk.Button(about_frame, text='还书', style='TButton',command=lambda: self.drop_toplevel())even_button.pack(pady=20)# 删除del_button = tkinter.ttk.Button(about_frame, text='删除', style='TButton', command=self.del_books)del_button.pack(pady=20)about_frame.pack_propagate(0)about_frame.place(relx=0.03, rely=0.01)# 双击事件 绑定事件要参数self.tree.bind("<Double-1>", self.click_double)def click_double(self, event):itm = self.tree.set(self.tree.focus())query_result = self.book.query_book(itm['id'])# print(query_result)self.toplevel_content(query_result[0]['content'])# 双击事件 双击图书显示书中介绍def toplevel_content(self, content):toplevel = tkinter.Toplevel()gui_center(toplevel, width=500, height=400)text = tkinter.Text(toplevel)text.insert(tkinter.INSERT, content)text.configure(state=tkinter.DISABLED)text.pack(fill='both', expand='True')# 搜索图书def search_v(self):query = self.book.query_book(self.search_entry.get_input_box())if query:for i in self.tree.get_children():self.tree.delete(i)for i in query:self.tree.insert('', tkinter.END,values=(i['id'], i['title'], i['author'], i['classify'], i['inventory']))else:tkinter.messagebox.showerror('提醒', '无查询结果!')# 删除图书def del_books(self):return_v = self.tree.set(self.tree.focus())self.book.del_book(return_v['id'])self.update_books()# 更新图书def update_books(self):all_book = self.book.read_book()for i in self.tree.get_children():self.tree.delete(i)for i in all_book:self.tree.insert('', tkinter.END,values=(i['id'], i['title'], i['author'], i['classify'], i['inventory']))def show_toplevel(self, flag):''':param flag: 1 添加  2 修改:return:'''self.toplevel = tkinter.Toplevel()gui_center(self.toplevel, width=600, height=500)id_label = tkinter.Label(self.toplevel, text='id', fg='red', font=("微软雅黑", 15, 'bold'))self.id_entry = tkinter.Entry(self.toplevel)id_label.pack()self.id_entry.pack()title_label = tkinter.Label(self.toplevel, text='书名', fg='red', font=("微软雅黑", 15, 'bold'))self.title_entry = tkinter.Entry(self.toplevel)title_label.pack(pady=4)self.title_entry.pack()author_label = tkinter.Label(self.toplevel, text='作者', fg='red', font=("微软雅黑", 15, 'bold'))self.author_entry = tkinter.Entry(self.toplevel)author_label.pack(pady=4)self.author_entry.pack()classify_label = tkinter.Label(self.toplevel, text='分类', fg='red', font=("微软雅黑", 15, 'bold'))self.classify_entry = tkinter.Entry(self.toplevel)classify_label.pack(pady=4)self.classify_entry.pack()inventory_label = tkinter.Label(self.toplevel, text='库存', fg='red', font=("微软雅黑", 15, 'bold'))self.inventory_entry = tkinter.Entry(self.toplevel)inventory_label.pack(pady=4)self.inventory_entry.pack()self.submit = tkinter.Button(self.toplevel, text='提交', fg='red', font=("微软雅黑", 15, 'bold'),)self.submit.pack(side='left')self.content_text = tkinter.Text(self.toplevel)self.content_text.pack(pady=4)# 添加if flag == 1:self.submit.configure(command=self.toplevel_submit)# 修改if flag == 2:itm = self.tree.set(self.tree.focus())if itm:self.id_entry.insert(0, itm['id'])self.title_entry.insert(0, itm['title'])self.author_entry.insert(0, itm['author'])self.classify_entry.insert(0, itm['classify'])self.inventory_entry.insert(0, itm['inventory'])content = self.book.query_book(itm['id'])self.content_text.insert('0.1', content[0]['content'])self.submit.configure(text='修改',command=lambda: self.modify_button(itm['id'], self.id_entry.get(), self.title_entry.get(),self.author_entry.get(),self.classify_entry.get(),self.inventory_entry.get(),self.content_text.get('1.0', tkinter.END)))else:self.toplevel.destroy()tkinter.messagebox.showerror('提醒', '请选择修改对象')# 修改图书def modify_button(self, old_id, id, title, author, classify, inventory, content):if self.book.mod_book(old_id, id, title, author, classify, inventory, content):tkinter.messagebox.showinfo('提醒', '修改成功', parent=self.toplevel)else:tkinter.messagebox.showerror('提醒', 'id重复', parent=self.toplevel)# 添加图书def toplevel_submit(self):get_id = self.id_entry.get()get_title = self.title_entry.get()get_author = self.author_entry.get()get_classify = self.classify_entry.get()get_inventory = self.inventory_entry.get()get_text = self.content_text.get('1.0', tkinter.END)# print(get_id, get_title, get_author, get_classify, get_inventory, get_text)tip = self.book.add_book(get_id, get_title, get_author, get_classify, get_inventory, get_text)if tip:tkinter.messagebox.showinfo('提醒', '添加成功', parent=self.toplevel)else:tkinter.messagebox.showinfo('提醒', '书库中已存在此书', parent=self.toplevel)# 借书窗口def borrow_toplevel(self):self.borrow_gui = tkinter.Toplevel()gui_center(self.borrow_gui, width=600, height=500)self.book_id_borrow_label = tkinter.Label(self.borrow_gui, text='id', font=("微软雅黑", 15, 'bold'))self.book_id_borrow_entry = tkinter.Entry(self.borrow_gui)self.book_id_borrow_label.place(relx=0.35, rely=0.1)self.book_id_borrow_entry.place(relx=0.4, rely=0.11)# 用户名self.user_borrow_label = tkinter.Label(self.borrow_gui, text='用户名', font=("微软雅黑", 15, 'bold'))self.user_borrow_entry = tkinter.Entry(self.borrow_gui)self.user_borrow_label.place(relx=0.28, rely=0.22)self.user_borrow_entry.place(relx=0.4, rely=0.23)# 数量 默认 1 最多2本self.num_v = tkinter.StringVar()self.num_borrow_option = tkinter.ttk.OptionMenu(self.borrow_gui, self.num_v, '1')self.num_borrow_label = tkinter.Label(self.borrow_gui, text='数量', font=("微软雅黑", 15, 'bold'))self.num_borrow_book = tkinter.Label(self.borrow_gui, text='本', font=("微软雅黑", 15, 'bold'))self.num_borrow_label.place(relx=0.29, rely=0.33)self.num_borrow_option.place(relx=0.4, rely=0.34)self.num_borrow_book.place(relx=0.48, rely=0.33)# 时间 默认30天 最多2个月self.time_v = tkinter.StringVar()self.time_borrow_option = tkinter.ttk.OptionMenu(self.borrow_gui, self.time_v, '15', '30')self.time_borrow_label = tkinter.Label(self.borrow_gui, text='期限', font=("微软雅黑", 15, 'bold'))self.time_borrow_day = tkinter.Label(self.borrow_gui, text='天', font=("微软雅黑", 15, 'bold'))self.time_borrow_label.place(relx=0.29, rely=0.43)self.time_borrow_option.place(relx=0.4, rely=0.44)self.time_borrow_day.place(relx=0.48, rely=0.43)# 确认借书self.s_borrow_button = tkinter.Button(self.borrow_gui, text='提交', font=("微软雅黑", 18, 'bold'),command=self.borrow_about)self.s_borrow_button.place(relx=0.4, rely=0.53)# 借书def borrow_about(self):op_user = UserOperation(1)op_record = Record()op_book = Book()v_id = self.book_id_borrow_entry.get()v_user = self.user_borrow_entry.get()t = ComputingTime()# 打印输入结果print(v_id, v_user, self.num_v.get(), self.time_v.get())name = op_book.query_book(v_id)# 首先查询图书if name:# 查借书用户if op_user.user_query(v_user):# 判断图书是否借完if int(name[0]['inventory']) <= 0:tkinter.messagebox.showerror('提醒', '图书已借完', parent=self.borrow_gui)return None# 判断用户是否还能借书if op_record.estimate_upper_limit(v_user):tkinter.messagebox.showerror('提醒', '用户借书已达到上限', parent=self.borrow_gui)return None# 对图书数量修改num = int(name[0]['inventory']) - int(self.num_v.get())op_book.mod_book(v_id, name[0]['id'], name[0]['title'], name[0]['author'], name[0]['classify'],str(num),name[0]['content'])# 添加到记录中op_record.record_books.append({'id': v_id, 'user': v_user, 'name': name[0]['title'], 'book_num': self.num_v.get(),'borrow_time': t.current_time(),'drop_time': t.return_book_time(int(self.time_v.get()))})op_record.write_record()tkinter.messagebox.showinfo('提醒', '借书成功!', parent=self.borrow_gui)else:tkinter.messagebox.showerror('提醒', '无此用户', parent=self.borrow_gui)else:tkinter.messagebox.showerror('提醒', '无此书', parent=self.borrow_gui)# 还书窗口def drop_toplevel(self):self.drop_gui = tkinter.Toplevel()gui_center(self.drop_gui, width=300, height=200)self.book_id_drop_label = tkinter.Label(self.drop_gui, text='id', font=("微软雅黑", 15, 'bold'))self.book_id_drop_entry = tkinter.Entry(self.drop_gui)self.book_id_drop_label.place(relx=0.2, rely=0.1)self.book_id_drop_entry.place(relx=0.3, rely=0.11)# 用户名self.user_drop_label = tkinter.Label(self.drop_gui, text='用户名', font=("微软雅黑", 15, 'bold'))self.user_drop_entry = tkinter.Entry(self.drop_gui)self.user_drop_label.place(relx=0.09, rely=0.25)self.user_drop_entry.place(relx=0.3, rely=0.26)self.s_drop_button = tkinter.Button(self.drop_gui, text='提交', font=("微软雅黑", 18, 'bold'),command=self.drop_about)self.s_drop_button.place(relx=0.4, rely=0.4)# 还书功能def drop_about(self):op_user = UserOperation(1)op_record = Record()op_book = Book()v_id = self.book_id_drop_entry.get()v_user = self.user_drop_entry.get()name = op_book.query_book(v_id)# 查图书if name:if op_user.user_query(v_user):all_drop_book = op_record.drop_book(v_id, v_user)if not all_drop_book:tkinter.messagebox.showerror('提醒', '该用户无需还书', parent=self.drop_gui)returnfor b in all_drop_book:# 对图书数量修改num = int(name[0]['inventory']) + int(b['book_num'])op_book.mod_book(b['id'], b['id'], name[0]['title'], name[0]['author'], name[0]['classify'],str(num),name[0]['content'])op_record.record_books.remove(b)op_record.write_record()tkinter.messagebox.showerror('提携', '还书成功', parent=self.drop_gui)else:tkinter.messagebox.showerror('提醒', '无此用户', parent=self.drop_gui)else:tkinter.messagebox.showerror('提醒', '无此图书', parent=self.drop_gui)if __name__ == '__main__':root = tkinter.Tk()style = tkinter.ttk.Style()note = tkinter.ttk.Notebook(root)main = Admin()style.configure('TNotebook.Tab', font=("微软雅黑", 20, 'bold'), foreground='red')root.geometry('800x600+450+150')note.add(main.main_show_frame, text='图书管理')note.pack(fill='both', expand='true')root.mainloop()

用户管理

用户管理相当于把图书换成了用户,其他都差不多。直接看代码。

import tkinter
from tkinter_book.other_fun.tip_entry import NewEntry
import tkinter.ttk
import tkinter.messagebox
from tkinter_book.other_fun.center_gui import gui_center
from tkinter_book.operation_data.user_operation import UserOperation'''对用户管理 添加 修改 删除
'''class ManagingUsers:def __init__(self):self.all_user = UserOperation(1)self.show_user()def show_user(self):self.main_show_frame = tkinter.Frame()about_frame = tkinter.LabelFrame(self.main_show_frame, width=160, height=500, text='功能区')show_book_frame = tkinter.Frame(self.main_show_frame, width=700, height=700)self.tree = tkinter.ttk.Treeview(show_book_frame, columns=('user', 'password', 'state'),show='headings', height=20, selectmode='browse')self.tree.heading('user', text='用户名', anchor='center')self.tree.heading('password', text='密码', anchor='center')self.tree.heading('state', text='状态', anchor='center')self.tree.column('user', anchor='center', width=80)self.tree.column('password', anchor='center', width=160)self.tree.column('state', anchor='center', width=120)for i in self.all_user.user_info['stu']:self.tree.insert('', tkinter.END, values=(i['user'], i['password'], i['state']))# 搜索框+按钮self.search_entry = NewEntry(show_book_frame, '请输入用户名')self.search_button = tkinter.Button(show_book_frame, text='搜索', command=self.search_v)self.update_button = tkinter.Button(show_book_frame, text='刷新', command=self.update_user)self.search_entry.place(relx=0.3, rely=0.05)self.search_button.place(relx=0.5, rely=0.04)self.update_button.place(relx=0.55, rely=0.04)self.tree.place(relx=0.15, rely=0.1)show_book_frame.place(relx=0.25, rely=0.01)# 按钮样式button_style = tkinter.ttk.Style()button_style.configure('TButton', font=("微软雅黑", 18, 'bold'), foreground='grey', width=8)# 添加add_button = tkinter.ttk.Button(about_frame, text='添加', style='TButton', command=lambda: self.show_toplevel(1))add_button.pack(pady=20)# 修改mod_button = tkinter.ttk.Button(about_frame, text='修改', style='TButton', command=lambda: self.show_toplevel(2))mod_button.pack(pady=20)# 删除del_button = tkinter.ttk.Button(about_frame, text='删除', style='TButton', command=self.del_user)del_button.pack(pady=20)about_frame.pack_propagate(0)about_frame.place(relx=0.03, rely=0.01)def search_v(self):query = self.all_user.user_query(self.search_entry.get_input_box())if query:for i in self.tree.get_children():self.tree.delete(i)self.tree.insert('', tkinter.END,values=(query['user'], query['password'], query['state']))else:tkinter.messagebox.showerror('提携', '无查询结果!')# 删除图书def del_user(self):return_v = self.tree.set(self.tree.focus())try:del_result = self.all_user.user_del(return_v['user'])if del_result:tkinter.messagebox.showinfo('提醒', '删除成功')except:tkinter.messagebox.showerror('提醒', '请选中删除目标')self.update_user()# 更新用户def update_user(self):all_user = self.all_user.user_info['stu']for i in self.tree.get_children():self.tree.delete(i)for i in all_user:self.tree.insert('', tkinter.END,values=(i['user'], i['password'], i['state']))def show_toplevel(self, flag):''':param flag: 1 添加  2 修改:return:'''self.toplevel = tkinter.Toplevel()gui_center(self.toplevel, width=450, height=400)user_label = tkinter.Label(self.toplevel, text='用户名', fg='red', font=("微软雅黑", 15, 'bold'))self.user_entry = tkinter.Entry(self.toplevel)user_label.pack(pady=20)self.user_entry.pack()password_label = tkinter.Label(self.toplevel, text='密码', fg='red', font=("微软雅黑", 15, 'bold'))self.password_entry = tkinter.Entry(self.toplevel)password_label.pack(pady=4)self.password_entry.pack()state_label = tkinter.Label(self.toplevel, text='状态', fg='red', font=("微软雅黑", 15, 'bold'))self.state_entry = tkinter.Entry(self.toplevel)state_label.pack(pady=4)self.state_entry.pack()self.submit = tkinter.Button(self.toplevel, text='提交', fg='red', font=("微软雅黑", 15, 'bold'),)self.submit.pack(pady=15)# 添加if flag == 1:self.submit.configure(command=self.toplevel_submit)# 修改if flag == 2:itm = self.tree.set(self.tree.focus())if itm:self.user_entry.insert(0, itm['user'])self.user_entry.configure(state='disable')self.password_entry.insert(0, itm['password'])self.state_entry.insert(0, itm['state'])self.submit.configure(text='修改',command=lambda: self.modify_button(itm['user'], self.user_entry.get(), self.password_entry.get(),self.state_entry.get(),))else:self.toplevel.destroy()tkinter.messagebox.showerror('提醒', '请选择修改对象')# 用户名不准修改def modify_button(self, user, old_password, new_password, state=0):if self.all_user.user_modify(user, old_password, new_password, state):tkinter.messagebox.showinfo('提醒', '修改成功', parent=self.toplevel)else:tkinter.messagebox.showerror('提醒', '修改失败', parent=self.toplevel)def toplevel_submit(self):get_user = self.user_entry.get()get_password = self.password_entry.get()get_state = self.state_entry.get()tip = self.all_user.user_add(get_user, get_password, get_state)if tip:tkinter.messagebox.showinfo('提醒', '添加成功', parent=self.toplevel)else:tkinter.messagebox.showinfo('提醒', '此用户已存在', parent=self.toplevel)if __name__ == '__main__':root = tkinter.Tk()style = tkinter.ttk.Style()note = tkinter.ttk.Notebook(root)main = ManagingUsers()style.configure('TNotebook.Tab', font=("微软雅黑", 20, 'bold'), foreground='red')root.geometry('800x600+450+150')note.add(main.main_show_frame, text='用户管理')note.pack(fill='both', expand='true')root.mainloop()

借书记录

管理员界面将显示所有用户的借书记录,如果传入的flag值为1则表示普通用户,只显示当前用户借的图书记录,flag为2则显示所有用户借的图书记录。界面将会显示用户的借书时间以及归还时间。

from tkinter_book.operation_data.record_book import Record
import tkinter
import tkinter.ttk
import time'''
显示已经借出去书的记录
'''class LogMessage:def __init__(self, flag, user=None):''':param flag: 1 普通用户 2 管理员:param user:'''self.flag = flagself.user = userself.show_gui()def show_gui(self):style = tkinter.ttk.Style()style.configure('t.TLabel', font=("微软雅黑", 18, 'bold'), foreground='blue')if self.flag == 1:self.main_show_frame = tkinter.Frame()self.log_books = Record()query_result = self.log_books.query_user(self.user)result = sorted(query_result, key=lambda x: x['borrow_time'], reverse=True)for i, v in enumerate(result):tkinter.ttk.Label(self.main_show_frame, text=v['id'], style='t.TLabel').grid(row=i, column=0, padx=5,pady=8)tkinter.ttk.Label(self.main_show_frame, text=v['user'], style='t.TLabel').grid(row=i, column=1, padx=5,pady=8)tkinter.ttk.Label(self.main_show_frame, text=v['name'], style='t.TLabel').grid(row=i, column=2, padx=8)tkinter.ttk.Label(self.main_show_frame, text='借', style='t.TLabel').grid(row=i, column=3)tkinter.ttk.Label(self.main_show_frame, text=self.handle_time(time.localtime(v['borrow_time'])),style='t.TLabel').grid(row=i, column=4)tkinter.ttk.Label(self.main_show_frame, text='还', style='t.TLabel').grid(row=i, column=5)tkinter.ttk.Label(self.main_show_frame, text=self.handle_time(time.localtime(v['drop_time'])),style='t.TLabel').grid(row=i, column=6)print('借书时间', time.localtime(v['borrow_time'])[:6], '还书时间', time.localtime(v['drop_time'])[:6])if self.flag == 2:self.main_show_frame = tkinter.Frame()self.log_books = Record()result = sorted(self.log_books.record_books, key=lambda x: x['borrow_time'], reverse=True)for i, v in enumerate(result):tkinter.ttk.Label(self.main_show_frame, text=v['id'], style='t.TLabel').grid(row=i, column=0, padx=5,pady=8)tkinter.ttk.Label(self.main_show_frame, text=v['user'], style='t.TLabel').grid(row=i, column=1, padx=5,pady=8)tkinter.ttk.Label(self.main_show_frame, text=v['name'], style='t.TLabel').grid(row=i, column=2, padx=8)tkinter.ttk.Label(self.main_show_frame, text='借', style='t.TLabel').grid(row=i, column=3)tkinter.ttk.Label(self.main_show_frame, text=self.handle_time(time.localtime(v['borrow_time'])),style='t.TLabel').grid(row=i, column=4)tkinter.ttk.Label(self.main_show_frame, text='还', style='t.TLabel').grid(row=i, column=5)tkinter.ttk.Label(self.main_show_frame, text=self.handle_time(time.localtime(v['drop_time'])),style='t.TLabel').grid(row=i, column=6)print('借书时间', time.localtime(v['borrow_time'])[:6], '还书时间', time.localtime(v['drop_time'])[:6])# 对时间格式修改 2023.7.21 18:05:12def handle_time(self, v_tuple):# 2023-7-24 15:20:30date = str(v_tuple[0]) + '-' + str(v_tuple[1]) + '-' + str(v_tuple[2])specific = str(v_tuple[3]) + ':' + str(v_tuple[4]) + ':' + str(v_tuple[5])# print(date + ' ' + specific)return date + ' ' + specificif __name__ == '__main__':root = tkinter.Tk()style = tkinter.ttk.Style()note = tkinter.ttk.Notebook(root)main = LogMessage(1, '123456')style.configure('TNotebook.Tab', font=("微软雅黑", 20, 'bold'), foreground='red')root.geometry('800x600+450+150')note.add(main.main_show_frame, text='已借记录')note.pack(fill='both', expand='true')root.mainloop()

更改密码

更改密码界面,如果传入的值flag为1,则是普通用户,普通用户的id是不允许修改,如果传入的值为2,则是管理员,管理员id允许修改,user参数管理员可以不传。

import tkinter
import tkinter.ttk
from tkinter_book.operation_data.user_operation import UserOperation
import tkinter.messageboxclass ChangePassword:def __init__(self, user, flag):self.user = userself.flag = flagself.gui_change_password()def gui_change_password(self):self.change_frame = tkinter.Frame()self.specific = tkinter.Frame(self.change_frame, width=450, height=500)self.specific.pack_propagate(0)self.specific.pack()self.old_user_label = tkinter.Label(self.specific, text='用户名', font=('微软雅黑', 18, 'bold'))self.old_user_entry = tkinter.Entry(self.specific, font=('微软雅黑', 18, 'bold'))self.old_label = tkinter.Label(self.specific, text='原密码', font=('微软雅黑', 18, 'bold'))self.old_entry = tkinter.Entry(self.specific, font=('微软雅黑', 18, 'bold'))self.old_user_label.pack()self.old_user_entry.pack(pady=5)self.old_label.pack()self.old_entry.pack(pady=5)self.new_label = tkinter.Label(self.specific, text='新密码', font=('微软雅黑', 18, 'bold'))self.new_entry = tkinter.Entry(self.specific, font=('微软雅黑', 18, 'bold'))self.new_label.pack()self.new_entry.pack(pady=5)self.submit_button = tkinter.Button(self.specific, text='提交', font=('微软雅黑', 20, 'bold'),command=self.submit_determine)self.submit_button.pack(pady=10)tip = tkinter.Label(self.specific, text='c站关注天天501', font=('', 10, 'bold')).pack(side='bottom')if self.flag == 1:# 插入用户名,并且不准修改self.old_user_entry.insert(0, self.user)self.old_user_entry.configure(state='disable')def submit_determine(self):oper = UserOperation(self.flag)# 获取值user_v = self.old_user_entry.get()old_password = self.old_entry.get()new_password = self.new_entry.get()print(user_v, old_password, new_password)if oper.user_query(user_v):if oper.user_modify(user_v, old_password, new_password):self.old_user_entry.delete(0, 'end')self.old_entry.delete(0, 'end')self.new_entry.delete(0, 'end')tkinter.messagebox.showinfo('提醒', '修改成功!')else:tkinter.messagebox.showerror('提醒', '密码错误!')else:tkinter.messagebox.showerror('提醒', '无此用户')if __name__ == '__main__':root = tkinter.Tk()style = tkinter.ttk.Style()note = tkinter.ttk.Notebook(root)change = ChangePassword('',1)style.configure('TNotebook.Tab', font=("微软雅黑", 20, 'bold'), foreground='red')root.geometry('800x600+450+150')note.add(change.change_frame, text='更改密码')note.pack(fill='both', expand='true')root.mainloop()

普通用户界面

首页、搜索、消息、更改密码这四个界面其实和管理员界面大同小异,这里就不过多的讲述了。

其他功能

数字时间显示

我们将用tkinter中的canvas模块来写一个类似数字闹钟的时间显示效果,首先我们知道绘制一个数字最多需要七笔,比如零,假设我们从某一个笔开始,如果这个数字有这个一笔,那我们就绘制,没有就跳过,那我们就可以完美的将每一个数字绘制下来。draw_num()绘制单个数字,将以上规律复现出来了。

import tkinter
from datetime import datetime'''
采用24进制  格式12:15
可以采用12小时进制  格式12:15
'''class Clock:def __init__(self, root, height=15, width=3, mode=24):# 以左上角坐标为准# 画布的宽高self.width = widthself.height = height# 画布的粗细self.line_distance = 5self.root = rootself.canvas = tkinter.Canvas(root, width=150, height=60)self.draw_clock()def draw_clock(self):# 删除之前绘制的self.canvas.delete('all')now = datetime.now()# 获取时间string = now.strftime('%H%M')# 小时self.draw_num(20, 10, int(string[0]))self.draw_num(20 + self.height * 2, 10, int(string[1]))# 两个点self.draw_interval(20 + self.height * 3.7, 20)self.draw_interval(20 + self.height * 3.7, 35)# 分钟self.draw_num(20 + self.height * 4.7, 10, int(string[2]))self.draw_num(20 + self.height * 6.7, 10, int(string[3]))def draw_num(self, x, y, num=0):# 总共分为7笔 每一笔if num in [2, 3, 4, 5, 6, 8, 9]:self.canvas.create_line(x + self.height, y + self.height, x, y + self.height,width=self.width)if num in [0, 4, 5, 6, 8, 9]:self.canvas.create_line(x - self.line_distance, y + self.height - self.line_distance,x - self.line_distance, y, width=self.width)if num in [0, 2, 3, 5, 6, 7, 8, 9]:self.canvas.create_line(x, y, x + self.height, y, width=self.width)if num in [0, 1, 2, 3, 4, 7, 8, 9]:self.canvas.create_line(x + self.line_distance + self.height, y,x + self.height + self.line_distance,y + self.height - self.line_distance,width=self.width)if num in [0, 1, 3, 4, 5, 6, 7, 8, 9]:self.canvas.create_line(x + self.line_distance + self.height,y + self.height,x + self.line_distance + self.height, y + self.height * 2,width=self.width)if num in [0, 2, 3, 5, 6, 8, 9]:self.canvas.create_line(x + self.height, y + self.height * 2,x, y + self.height * 2,width=self.width)if num in [0, 2, 6, 8]:self.canvas.create_line(x - self.line_distance, y + self.height * 2,x - self.line_distance, y + self.height,width=self.width)def draw_interval(self, x, y):self.canvas.create_rectangle(x, y, x + 5, y + 5, fill='black')if __name__ == '__main__':root = tkinter.Tk()root.geometry('500x500+350+150')n = Clock(root)n.canvas.pack()root.mainloop()

加载画面显示

登录成功后会出现一个加载界面,这个效果实现比较简单,要用到Progressbar(),创建进度条,show()函数用for循环不断改变Progressbar()里面的值,同时需要更新界面,以达到动态显示的效果。当进度条加满时画面结束。

from tkinter_book.other_fun.center_gui import gui_center
import tkinter.ttk
import tkinter
import random
import timeclass Loading(tkinter.Tk):def __init__(self):super(Loading, self).__init__()# 居中显示gui_center(self, 100, 14)# 窗口透明self.attributes('-alpha', 0.8)# 无边框self.overrideredirect(True)self.loading_gui()self.mainloop()# 创建进度条def loading_gui(self):self.pro = tkinter.ttk.Progressbar(self, value=0, max=100, length=100)self.pro.pack()self.show()# 动态加载进度条def show(self):v = random.randint(1, 5)for i in range(100):v += random.randint(1, 16)self.pro.config(value=v)# 更新self.update()time.sleep(0.09)if v >= 100:print('结束了')self.destroy()returnif __name__ == '__main__':Loading()

输入框提示词

输入框提示词效果比较简单,把Entry重写,当光标不在的输入框的时候,显示提示词,光标在的时候就不显示,最后我们还可以获取到输入框的值。

from tkinter import *class NewEntry(Entry):def __init__(self, master=None, placeholder="提示词", color="grey"):super().__init__(master)# 提示输入self.placeholder = placeholderself.placeholder_color = color# 输入框背景self.default_fg_color = self["fg"]# 光标聚集self.bind("<FocusIn>", self.foc_in)# 光标离开self.bind("<FocusOut>", self.foc_out)self.put_placeholder()# 重写插入提示词def put_placeholder(self):self.insert(0, self.placeholder)self["fg"] = self.placeholder_color# 光标在的时候 删除提示词def foc_in(self, *args):if self["fg"] == self.placeholder_color:self.delete(0, END)self["fg"] = self.default_fg_color# 光标离开插入提示词def foc_out(self, *args):if not self.get():self.put_placeholder()# 获取输入框的值def get_input_box(self):print(self.get())return self.get()

界面居中显示

首先获取屏幕的宽高,那我们就有了界面宽高和屏幕的宽高,那就很容易就能计算出界面居中的位置。

# 窗口居中
def gui_center(win, width=300, height=450):# 获取屏幕的宽高screen_width = win.winfo_screenwidth()screen_height = win.winfo_screenheight()x = int(screen_width / 2 - width / 2)y = int(screen_height / 2 - height / 2)win.geometry(f'{width}x{height}+{x}+{y}')

借书时间和还书时间记录

这里用到了time模块,用于记录时间,根据时间戳来计算还书和借书的时间。

import timeclass ComputingTime:def __init__(self):pass# 返回当前时间def current_time(self):return time.time()# 还书时间def return_book_time(self, days):# 根据天数计算归还时间# print(time.localtime(self.current_time()+self.count_second(30)))borrow = self.current_time()return borrow + self.count_second(days)# 计算十位时间戳def count_second(self, days):return int(days) * 24 * 60 * 60# 判断是否到了还书时间def compare(self, back):current = self.current_time()if current >= back:return Trueelse:return Falseif __name__ == '__main__':clock = ComputingTime()print(clock.return_book_time(20))

公告栏数据操作

公告栏比较简单,当第一次运行时会写入数据并保存为json格式。当我们需要对数据进行操作时,可以读取或写入,以达到重新发布公告栏的效果。

import osdef first_write(txt='关注天天501'):name = '公告栏.txt'if not (name in os.listdir()):print('开始初次写入用户信息')with open(name, mode='w', encoding='utf-8') as f:f.write(txt)return# 写入数据
def announcement_write(txt):with open('公告栏.txt', mode='w', encoding='utf-8') as f:f.write(txt)# 读取数据
def announcement_read():with open('公告栏.txt', mode='r', encoding='utf-8') as f:return f.read()

结尾

结束也是开始。本文到这就结束了,想要完整代码的,点赞+关注,私信我就可以了。感谢大家的支持和关注。
————2023.8.11 21:00

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/34655.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot异步任务

在Service类声明一个注解Async作为异步方法的标识 package com.qf.sping09test.service;import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service;Service public class AsyncService {//告诉spring这是一个异步的方法Asyncp…

JavaWeb 中对 HTTP 协议的学习

HTTP1 Web概述1.1 Web和JavaWeb的概念1.2 JavaWeb技术栈1.2.1 B/S架构1.2.2 静态资源1.2.3 动态资源1.2.4 数据库1.2.5 HTTP协议1.2.6 Web服务器 1.3 Web核心 2 HTTP2.1 简介2.2 请求数据格式2.2.1 格式介绍2.2.2 实例演示 2.3 响应数据格式2.3.1 格式介绍2.3.2 响应状态码2.3.…

面试热题(合并两个有序列表)

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 合并链表这类型题也是比较经典的题了&#xff0c;因为链表是由指针相互指向而确定位置&#xff0c;所以我们只需要改变某些节点的指针便可以做到对链表进行排序 今天这个方法…

Spring Bean 生命周期的执行流程

问题描述 Spring 生命周期全过程大致分为五个阶段&#xff1a; 1、创建前准备阶段 2、创建实例阶段 3、依赖注入阶段 4、 容器缓存阶段 5、销毁实例阶段 下图是 Spring Bean 生命周期完整流程图&#xff0c;其中对每个阶段的具体操作做了详细介绍&#xff1a; 一、创建前准备阶…

阶梯费用计算(配置化_最小demo)

本文旨在提供一种配置化思路计算阶梯费用&#xff0c;更高级的做法则是通过数据库配置&#xff0c;注册中心等&#xff1b;在表达式上可以采用自定义或者spel表达式等其他方式进行处理&#xff1b;(代码仅展示最小demo,部分不完善地方自行补充) 思路&#xff1a;N个区间对应N个…

Spring Boot 项目应用消息服务器RabbitMQ(简单介绍)

一、背景 本章讲述的是在用户下单环节&#xff0c;消息服务器RabbitMQ 的应用 1.1 消息服务器的应用 在写一个电商项目的小demo&#xff0c;在电商项目中&#xff0c;消息服务器的应用&#xff1a; 1、订单状态通知&#xff1a;当用户下单、支付成功、订单发货、订单完成等…

【MFC】10.MFC六大机制:RTTI(运行时类型识别),动态创建机制,窗口切分,子类化-笔记

运行时类信息&#xff08;RTTI&#xff09; C: ##是拼接 #是替换成字符串 // RTTI.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> #include <afxwin.h>#ifdef _DEBUG #define new DEBUG_NEW #endifCWinApp th…

六种不同的CRM系统类型分别有哪些特点?

企业想要管理销售&#xff0c;可以选择CRM系统&#xff1b;企业想要优化业务流程&#xff0c;可以选择CRM系统&#xff1b;企业想要提高收入&#xff0c;可以选择CRM系统。下面来说说&#xff0c;CRM是什么&#xff1f;六种常见CRM系统类型对比。 什么是CRM&#xff1f; CRM是…

优秀的 Modbus 从站(从机、服务端)仿真器、串口调试工具

文章目录 优秀的 Modbus 从站&#xff08;从机、服务端&#xff09;仿真器、串口调试工具主要功能软件截图 优秀的 Modbus 从站&#xff08;从机、服务端&#xff09;仿真器、串口调试工具 官网下载地址&#xff1a;http://www.redisant.cn/mse 主要功能 支持多种Modbus协议…

Java课题笔记~ Spring 集成 MyBatis

Spring 集成 MyBatis 将 MyBatis 与 Spring 进行整合&#xff0c;主要解决的问题就是将 SqlSessionFactory 对象交由 Spring 来管理。所以该整合&#xff0c;只需要将 SqlSessionFactory 的对象生成器SqlSessionFactoryBean 注册在 Spring 容器中&#xff0c;再将其注入给 Dao…

多目标优化算法之樽海鞘算法(MSSA)

樽海鞘算法的主要灵感是樽海鞘在海洋中航行和觅食时的群聚行为。相关文献表示&#xff0c;多目标优化之樽海鞘算法的结果表明&#xff0c;该算法可以逼近帕雷托最优解&#xff0c;收敛性和覆盖率高。 通过给SSA算法配备一个食物来源库来解决第一个问题。该存储库维护了到目前为…

Docker镜像查看下载删除镜像文件的相关命令

1.镜像相关命令 本地查看有哪些镜像文件&#xff1a; docker images镜像的名称就是我们常见的一些软件&#xff0c;镜像相当于把软件和软件所需要的运行环境打包到一个镜像文件里面&#xff0c;将来在通过这个镜像文件创建出对应的容器&#xff0c;容器有了以后这些软件自动的…

java线程的优先级、守护线程的概念

1.线程的调度 抢占式调度 非抢占式调度 1.1 抢占式调度 优先级越高&#xff0c;抢到cpu的概率越高 1.2 守护线程 守护线程&#xff0c;非守护线程。当其他的非守护线程执行完毕以后&#xff0c;守护线程会陆续结束。 守护线程的应用场景

插入排序(Java实例代码)

目录 插入排序 一、概念及其介绍 二、适用说明 三、过程图示 四、Java 实例代码 InsertionSort.java 文件代码&#xff1a; 插入排序 一、概念及其介绍 插入排序(InsertionSort)&#xff0c;一般也被称为直接插入排序。 对于少量元素的排序&#xff0c;它是一个有效的算…

CNN(四):ResNet与DenseNet结合--DPN

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 前面实现了ResNet和DenseNet的算法&#xff0c;了解了它们有各自的特点&#xff1a; ResNet&#xff1a;通过建立前面层与后面层之间的“短路…

TSINGSEE青犀视频安防监控视频平台EasyCVR设备在线,视频无法播放的原因排查

可支持国标GB28181、RTMP、RTSP/Onvif、海康Ehome、海康SDK、大华SDK、宇视SDK等多种协议接入的安防监控视频平台EasyCVR基于云边端一体化架构&#xff0c;具有强大的数据接入、处理及分发能力&#xff0c;可在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、…

IDEA全局设置MyBatis中写SQL语句提示

第一步&#xff1a;把这两个设置改成MySQL即可&#xff1a; 第二步&#xff1a;找到设置>编辑器>语言注入>店家加号&#xff0c;选择MySQL

微信小程序在使用vant组件库时构建npm报错

在跟着vant官方进行使用步骤一步步操作时&#xff0c;由于要构建NPM&#xff0c;但NPM包在App配置文件的外部 所以在做下图这一步时&#xff1a; 接着再进行npm构建时会报错 message:发生错误 Error: F:\前端学习\前端框架\小程序\project\demo\miniprogram解决方法 &#xf…

Java:正则表达式书写规则及相关案例:检验QQ号码,校验手机号码,邮箱格式,当前时间

正则表达式 目标:体验一下使用正则表达式来校验数据格式的合法性。需求:校验QQ号码是否正确&#xff0c;要求全部是数字&#xff0c;长度是(6-20&#xff09;之间&#xff0c;不能以0开头 首先用自己编写的程序判断QQ号码是否正确 public static void main(String[] args) {Sy…

递归、搜索与回溯算法

一.递归 &#xff08;1&#xff09;汉诺塔问题 当n2时&#xff0c;要将A中最下面盘子上方的盘子放到B上&#xff0c;最下面盘子放到C上&#xff0c;再将B上的盘子通过A放到C即可&#xff1b; 当n3时&#xff0c;要将A中最下面盘子上方的盘子放到B上&#xff0c;最下面盘子放到…