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

news2024/12/23 23:01:32

文章目录

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

前文

本文将用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']:
                # 也可用 find
                if 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'] = id
            new_book['title'] = title
            new_book['author'] = author
            new_book['classify'] = classify
            new_book['inventory'] = inventory
            new_book['content'] = content
            self.books.append(new_book)
            print('添加', new_book)
            self.write_book()
            return True
        else:
            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'] = id
            result[0]['title'] = title
            result[0]['author'] = author
            result[0]['classify'] = classify
            result[0]['inventory'] = inventory
            result[0]['content'] = content
            self.write_book()
            return True
        return False

    def 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.books
    def 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 = flag
        self.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 True
            if self.flag == 2:
                self.user_info['admin'].append({'user': str(user), 'password': str(password)})
                self.write_user()
                return True
        else:
            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'] = user
                            i['password'] = new_password
                            i['state'] = str(state)
                            self.write_user()
                            return True
                if self.flag == 2:
                    for i in self.user_info['admin']:
                        if result['user'] == i['user']:
                            i['user'] = user
                            i['password'] = new_password
                            self.write_user()
                            return True

    def 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 True

    def user_query(self, user):
        if self.flag == 1:
            for i in self.user_info['stu']:
                if user == i['user']:
                    print('查找成功!')
                    return i
            else:
                return None
        if self.flag == 2:
            for i in self.user_info['admin']:
                if user == i['user']:
                    print('查找成功!')
                    return i
            else:
                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 json


def 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)
	# 借书上限为2
    def estimate_upper_limit(self, user):
        borrow_books = []
        for book in self.record_books:
            if book['user'] == user:
                if int(book['book_num']) > 1:
                    return True
                else:
                    borrow_books.append(book)
        if len(borrow_books) >= 2:
            return True
        return 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_books
        return False

    # 查询用户
    def query_user(self, user):
        dance = []
        for o in self.record_books:
            if o['user'] == user:
                dance.append(o)
        print(dance)
        return dance

if __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_center

class 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 = 0
        self.flag = False
        self.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('错误提醒', '此账号不存在!')
                return
            if result['state'] != '0':
                tkinter.messagebox.showerror('提醒', '此账号已经封禁,请联系管理员')
                return

            if e_get_u == result['user'] and e_get_p == result['password']:
                self.destroy()
                Loading()
                # print('登录成功!')
                self.flag = True

            elif e_get_u == result['user'] and e_get_p != result['password']:
                self.num += 1
                if self.num >= 3:
                    print('错误提醒', '账号锁定,请联系管理员!')
                    self.num = 0
                    result['state'] = '1'
                    self.all_info.write_user()
                    tkinter.messagebox.showerror('错误提醒', '此账号已经封禁,请联系管理员')
                    return
                tkinter.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('错误提醒', '此账号不存在!')
                return

            if e_get_u == result['user'] and e_get_p == result['password']:
                self.destroy()
                Loading()
                print('登录成功!')
                self.flag = True
                return 2

            elif 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_pict


def 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'] = city
        for 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//' + img
            else:
                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 data
    else:
        print('搜索无效')
        data['city'] = 'None'
        for i in range(8):
            data['teacher'].append(['None', 'None', 'None', 'None', 'None'])
        return data


if __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.messagebox


class HomePage:
    def __init__(self, flag):
        self.weather_lists = []
        self.flag = flag
        self.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)
                    return
                for 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 = flag
        self.user = user
        self.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:12
    def handle_time(self, v_tuple):
        # 2023-7-24 15:20:30
        date = 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 + ' ' + specific


if __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.messagebox


class ChangePassword:
    def __init__(self, user, flag):
        self.user = user
        self.flag = flag

        self.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 = width
        self.height = height
        # 画布的粗细
        self.line_distance = 5
        self.root = root
        self.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 time


class 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()
                return


if __name__ == '__main__':
    Loading()

输入框提示词

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

from tkinter import *


class NewEntry(Entry):
    def __init__(self, master=None, placeholder="提示词", color="grey"):
        super().__init__(master)
        # 提示输入
        self.placeholder = placeholder
        self.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 time


class 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 True
        else:
            return False


if __name__ == '__main__':
    clock = ComputingTime()
    print(clock.return_book_time(20))

公告栏数据操作

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

import os


def 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.coloradmin.cn/o/866264.html

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

相关文章

Nuitka实战

安装Nuitka pip install -U nuitka 安装好之后查看版本 python -m nuitka --version 显示gcc版本太低&#xff0c;与nuitka不兼容&#xff0c;所以我们要升级gcc版本 升级之前&#xff0c;先查看一下gcc版本信息 gcc --version 可以看到&#xff0c;Centos 7.7默认gcc版本为…

SRE之前端服务器的负载均衡

写在前面 今天和小伙伴们分享一些前端服务器的负载均衡技术内容为结合《 SRE Google运维解密》 整理&#xff1a; 涉及DNS 负载均衡VIP 负载均衡反向代理负载均衡 理解不足小伙伴帮忙指正 傍晚时分&#xff0c;你坐在屋檐下&#xff0c;看着天慢慢地黑下去&#xff0c;心里寂寞…

人大金仓三大兼容:Oracle迁移无忧

企业级应用早期的架构模式是C/S&#xff08;Client/Server&#xff09;模式&#xff0c;Client做人机交互逻辑的呈现&#xff0c;Sever做业务计算逻辑的实现。这就类似餐馆的运作模式&#xff0c;Client是前台的服务员提供点菜和上菜服务&#xff0c;而Server则是后厨完成菜品的…

Java基础篇--修饰符

Java语言提供了很多修饰符&#xff0c;主要分为以下两类&#xff1a; 访问控制修饰符 非访问修饰符 访问控制修饰符 private&#xff1a;私有访问权限&#xff0c;用于修饰类的属性和方法。被private修饰的成员只能在本类中进行访问。default&#xff08;默认访问权限&…

spark 图计算 助力解决 dataframe中的链式依赖

链式依赖说明 name newName a b c d b c 我们需要的结果 即我们可以支持获取到链式转换的 起点 重点 以及链式的中间转换过程顺序数组. 特别说明: 出版只支持 单向 无分叉的图,其他复杂场景暂时未测试. 场景举例: 比如某件商品价格变化,我们需要知…

原始套接字编程(AF_PACKET+SOCK_RAW)模拟一个PING

1. 背景 最近看一个客户的代码片段&#xff0c;发现他在用原始套接字编程&#xff0c;一般学习套接字都是流式套接字和数据报套接字&#xff0c;本来也不是搞网络的&#xff0c;原始套接字了解得很少&#xff0c;借着这次机会&#xff0c;自己来学习一下原始套接字编程。 2. …

函数的模拟实现

题一&#xff1a; 模拟实现strncpy #include <stdio.h>void my_strncpy(char* arr2, char* arr1, size_t num){int i 0;for (i 0; i < num; i){*(arr2 i) *(arr1 i);}}int main(){char arr1[] "hello liangzai";char arr2[10] { 0 };//strncpy(ar…

包管理工具详解npm 、 yarn 、 cnpm 、 npx 、 pnpm(2023)

1、包管理工具npm &#xff08;1&#xff09;包管理工具npm&#xff1a; Node Package Manager&#xff0c;也就是Node包管理器&#xff1b;但是目前已经不仅仅是Node包管理器了&#xff0c;在前端项目中我们也在使用它来管理依赖的包&#xff1b;比如vue、vue-router、vuex、…

3.6 Spring MVC文件上传

1. 文件上传到本地 实现方式 Spring MVC使用commons-fileupload实现文件上传&#xff0c;注意事项如下&#xff1a; l HTTP请求方法是POST。 l HTTP请求头的Content-Type是multipart/form-data。 SpringMVC配置 配置commons-fileupload插件的文件上传解析器CommonsMultip…

搭建servlet服务

目录 servlet的生命周期 配置tomcat环境 创建web后端项目 配置web.xml http请求 get和post 其他请求 http响应 Servlet是Server Applet的简称&#xff0c;意思为用Java编写的服务器端的程序&#xff0c;它运行在web服务器中&#xff0c;web服务器负责Servlet和客户的通…

Springboot开发常用注解

文章目录 1.RestController2.Data3.RequestMapping4.Builder 1.RestController RestController注解其实就是将 return 中的内容以 JSON字符串的形式返回客户端 controller的详解 2.Data Data详解 3.RequestMapping RequestMapping 4.Builder Builder

文件系统目录结构

1. 目录结构 linux的文件系统是采用级层式的树状目录结构&#xff0c;在此结构中的最上层是根目录/ &#xff0c;然后在此目录下再创建其他的目录。 在linux中&#xff0c;一切皆文件(Linux将所有的设备、文件、进程等都当做文件来处理) 2. 目录作用具体介绍 目录名解析/b…

访企聚力促创新:长安大学来访闪马智能

7月31日&#xff0c;长安大学运输工程学院院长葛颖恩教授、学院副书记李婷以及学办主任董彬一行来访闪马智能&#xff0c;闪马智能创始人兼CEO彭垚、城市交通行业总经理兼营销副总裁詹诚以及公共交通行业总经理熊天圣等出席了本次交流会。 长安大学运输工程学院院长葛颖恩教授…

软考考点之Mccabe度量计算及路径覆盖

软考考点之Mccabe度量计算及路径覆盖 [2023年上半年] 34、35、以下流程图中&#xff0c;至少需要(34)个测试用例才能覆盖所有路径。采用McCabe方法计算程序复杂度为(35) A&#xff0e;3B&#xff0e;4C&#xff0e;5D&#xff0e;6(35)A&#xff0e;2B&#xff0e;3C&#xf…

【框架类】—Vue3的生命周期

一、生命周期的相关函数 onBeforeMount 页面渲染之前 和 onMounted渲染之后 示例 <template><div class"test"><div ref"el">组件初始化</div></div> </template> <script> //按需引入所需方法 import { ref,…

sudo root命令不在sudoers文件中。此事将被报告。全网比较详细版本,解决报错问题步骤较多

我在使用个人用户zhang&#xff08;非root用户&#xff09;时&#xff0c;在执行其他命令时&#xff0c;使用sudo命令来执行的时候&#xff0c;需要验证当前用户的密码&#xff0c; 输入了之后&#xff0c;提示“zhang‘ 不在sudoers文件中&#xff0c;此事将被报告” 分析原…

JAVA设计模式----原型设计模式

文章目录 一、简介二、实现方式三、原型模式的注意事项浅拷贝与深拷贝浅拷贝深拷贝一、简介 定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。 类型:创建类模式 类图: 原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Protot…

eNSP:ibgp的破水平切割练习

实验要求&#xff1a; 拓扑展示&#xff1a; 命令操作&#xff1a; R1&#xff1a; <Huawei>sys [Huawei]sys r1 [r1]int g 0/0/1 [r1-GigabitEthernet0/0/1]ip add 12.1.1.1 24 [r1-GigabitEthernet0/0/1]int lo0 [r1-LoopBack0]ip add 1.1.1.1 24 [r1-LoopBack0]osp…

dingding机器人

“自定义机器人”只支持消息发送&#xff0c;自动回复需要“企业内部机器人” 消息发送 import requests import jsonres requests.post(https://oapi.dingtalk.com/robot/send?access_token036a339axxx,data json.dumps({"text": {"content":"h…