首页 > 编程语言 >python图书管理系统

python图书管理系统

时间:2025-01-19 15:57:21浏览次数:3  
标签:__ 管理系统 python self cursor book conn 图书 tk

效果展示

概述

本教程将引导你构建一个基于Python的图书管理系统,该系统使用Tkinter作为图形用户界面(GUI),并利用SQLite数据库存储和管理图书信息。通过本教程,你将学习如何实现添加、编辑、删除以及查询图书的功能。

准备工作

确保你的计算机上安装了Python 3.x版本。由于我们使用的是标准库tkintersqlite3,所以无需额外安装其他依赖包。如果你使用的是非Windows操作系统,可能需要单独安装tkinter

步骤 1: 导入必要的模块

首先,我们需要导入所有必需的模块。这包括用于GUI开发的tkinter及其子模块ttk(主题工具包),以及用于消息框和对话框的messageboxsimpledialog。同时,我们还会导入sqlite3来处理数据库操作,以及pathlib来处理文件路径。

import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import sqlite3
from pathlib import Path

步骤 2: 数据库初始化与连接

接下来定义两个函数:init_db()用于初始化数据库表结构;get_db_connection()用于获取数据库连接。init_db()会在第一次运行程序时创建名为Library.db的数据库文件,并在其中创建Books表,如果它不存在的话。

def init_db():
    """初始化数据库表结构"""
    with get_db_connection() as conn:
        cursor = conn.cursor()
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS Books (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                author TEXT NOT NULL,
                publisher TEXT,
                isbn TEXT UNIQUE,
                stock INTEGER DEFAULT 0
            )
        ''')
        conn.commit()

def get_db_connection():
    """获取数据库连接"""
    conn = sqlite3.connect(Path(__file__).parent / 'Library.db')
    conn.row_factory = sqlite3.Row
    return conn

步骤 3: 创建主应用程序类 BookManagerApp

BookManagerApp是整个应用的核心类,继承自tk.Tk,负责构建界面并管理各个窗口之间的交互。

  • 构造函数 (__init__) 设置了窗口标题、尺寸和背景颜色,并调用init_db()确保数据库已准备好。
  • 它还设置了菜单栏、工具栏,并配置了样式以美化组件外观。
  • 最后,它创建了一个Treeview小部件用来显示图书列表,并通过load_books()加载现有书籍数据。
class BookManagerApp(tk.Tk):
    """主应用程序类"""

    def __init__(self):
        super().__init__()
        self.title("图书管理系统")
        self.geometry("800x600")
        self.configure(bg='#EAEAEA')  # 设置背景颜色

        # 初始化数据库
        init_db()

        # 创建顶部菜单栏和工具栏...
        menubar = tk.Menu(self)
        file_menu = tk.Menu(menubar, tearoff=0)
        file_menu.add_command(label="退出", command=self.quit)
        menubar.add_cascade(label="文件", menu=file_menu)

        book_menu = tk.Menu(menubar, tearoff=0)
        book_menu.add_command(label="添加图书", command=self.open_add_book_window)
        book_menu.add_command(label="编辑图书", command=self.edit_selected_book)
        book_menu.add_command(label="删除图书", command=self.delete_selected_books)
        book_menu.add_command(label="查询图书", command=self.open_search_window)  # 添加查询命令
        menubar.add_cascade(label="图书", menu=book_menu)

        self.config(menu=menubar)

        # 创建工具栏
        toolbar = ttk.Frame(self, style='TFrame')
        add_button = ttk.Button(toolbar, text="添加", command=self.open_add_book_window, style='TButton')
        edit_button = ttk.Button(toolbar, text="编辑", command=self.edit_selected_book, style='TButton')
        delete_button = ttk.Button(toolbar, text="删除", command=self.delete_selected_books, style='TButton')
        search_button = ttk.Button(toolbar, text="查询", command=self.open_search_window, style='TButton')  # 添加查询按钮
        add_button.pack(side=tk.LEFT, padx=5, pady=5)
        edit_button.pack(side=tk.LEFT, padx=5, pady=5)
        delete_button.pack(side=tk.LEFT, padx=5, pady=5)
        search_button.pack(side=tk.LEFT, padx=5, pady=5)  # 查询按钮布局
        toolbar.pack(side=tk.TOP, fill=tk.X)

        # 样式配置
        style = ttk.Style()
        style.theme_use('clam')  # 使用预定义的主题
        style.configure('TFrame', background='#EAEAEA')
        style.configure('TButton', font=('Arial', 12), foreground='black', background='#4CAF50')
        style.map('TButton', foreground=[('active', 'white')],
                  background=[('active', '#45a049')])
        style.configure('Treeview', font=('Arial', 12), rowheight=25)
        style.configure('Treeview.Heading', font=('Arial', 12, 'bold'))

        # 创建图书列表视图
        columns = ('id', 'title', 'author', 'publisher', 'isbn', 'stock')
        self.book_tree = ttk.Treeview(self, columns=columns, show='headings', style='Treeview')
        for col in columns:
            self.book_tree.heading(col, text=col.capitalize())
            self.book_tree.column(col, width=120, anchor=tk.CENTER)
        self.book_tree.pack(expand=True, fill=tk.BOTH, padx=10, pady=10)

        self.load_books()

步骤 4: 实现增删改查功能

增加图书

为了增加新的图书记录,我们创建了一个AddBookWindow类,提供给用户输入新书信息的界面。用户填写必要字段后点击“保存”按钮,即可将新书信息保存至数据库。

class AddBookWindow(tk.Toplevel):
    """添加新书窗口类"""

    def __init__(self, parent):
        super().__init__(parent)
        self.title("添加新书")
        self.geometry("400x300")
        self.configure(bg='#EAEAEA')

        # 输入框
        self.entries = {}
        fields = ['标题', '作者', '出版社', 'ISBN', '库存']
        for i, field in enumerate(fields):
            label = ttk.Label(self, text=field, background='#EAEAEA')
            label.grid(row=i, column=0, padx=5, pady=5, sticky=tk.W)
            entry = ttk.Entry(self)
            entry.grid(row=i, column=1, padx=5, pady=5)
            self.entries[field] = entry

        save_button = ttk.Button(self, text="保存", command=self.save_book)
        save_button.grid(row=len(fields), columnspan=2, pady=10)

    def save_book(self):
        """保存新书信息至数据库"""
        data = {key: entry.get() for key, entry in self.entries.items()}
        try:
            with get_db_connection() as conn:
                cursor = conn.cursor()
                cursor.execute('''
                    INSERT INTO Books (title, author, publisher, isbn, stock)
                    VALUES (?, ?, ?, ?, ?)
                ''', (data['标题'], data['作者'], data['出版社'], data['ISBN'], int(data['库存'])))
                conn.commit()
            self.destroy()
            self.master.load_books()
        except Exception as e:
            messagebox.showerror("错误", str(e))

编辑图书

EditBookWindow类允许用户修改已有图书的信息。它会根据提供的book_id从数据库中检索出对应的图书信息,并填充到表单中供用户编辑。

class EditBookWindow(tk.Toplevel):
    """编辑图书窗口类"""

    def __init__(self, parent, book_id):
        super().__init__(parent)
        self.title("编辑图书")
        self.geometry("400x300")
        self.configure(bg='#EAEAEA')

        self.book_id = book_id
        self.entries = {}
        fields_mapping = {
            '标题': 'title',
            '作者': 'author',
            '出版社': 'publisher',
            'ISBN': 'isbn',
            '库存': 'stock'
        }

        # 从数据库获取要编辑的图书信息
        with get_db_connection() as conn:
            cursor = conn.cursor()
            cursor.execute('SELECT * FROM Books WHERE id=?', (book_id,))
            book = cursor.fetchone()

        if not book:
            messagebox.showerror("错误", "找不到指定ID的图书!")
            self.destroy()
            return

        # 预填充表单字段
        for i, field in enumerate(fields_mapping.keys()):
            label = ttk.Label(self, text=field, background='#EAEAEA')
            label.grid(row=i, column=0, padx=5, pady=5, sticky=tk.W)
            entry = ttk.Entry(self)

            # 使用映射后的列名访问数据
            entry.insert(0, book[fields_mapping[field]])  # 使用映射后的列名

            entry.grid(row=i, column=1, padx=5, pady=5)
            self.entries[field] = entry

        save_button = ttk.Button(self, text="保存", command=self.update_book)
        save_button.grid(row=len(fields_mapping), columnspan=2, pady=10)

    def update_book(self):
        """更新图书信息至数据库"""
        data = {key: entry.get() for key, entry in self.entries.items()}
        try:
            with get_db_connection() as conn:
                cursor = conn.cursor()
                cursor.execute('''
                    UPDATE Books SET title=?, author=?, publisher=?, isbn=?, stock=?
                    WHERE id=?
                ''', (data['标题'], data['作者'], data['出版社'], data['ISBN'], int(data['库存']), self.book_id))
                conn.commit()
            self.destroy()
            self.master.load_books()  # 刷新主界面中的图书列表
        except Exception as e:
            messagebox.showerror("错误", str(e))

删除图书

BookManagerApp类中定义了delete_selected_books()方法,用于删除选中的图书记录。当用户选择了要删除的图书并确认后,这些记录将被从数据库中移除,并且界面上也会同步更新。

def delete_selected_books(self):
    """删除选中的图书记录"""
    selected_items = self.book_tree.selection()
    if not selected_items:
        messagebox.showwarning("警告", "请选择要删除的图书!")
        return

    confirm = messagebox.askyesno("确认删除", "确定要删除这些图书吗?")
    if not confirm:
        return

    book_ids = [self.book_tree.item(item)['values'][0] for item in selected_items]
    with get_db_connection() as conn:
        cursor = conn.cursor()
        cursor.executemany('DELETE FROM Books WHERE id=?', [(id,) for id in book_ids])
        conn.commit()

    for item in selected_items:
        self.book_tree.delete(item)

查询图书

SearchWindow类提供了用户根据标题、作者、出版社或ISBN部分匹配来查找图书的功能。用户输入关键字后点击“查询”按钮,系统将在数据库中查找符合条件的图书并将结果展示出来。

class SearchWindow(tk.Toplevel):
    """查询窗口类"""

    def __init__(self, parent):
        super().__init__(parent)
        self.title("查询图书")
        self.geometry("400x300")
        self.configure(bg='#EAEAEA')

        # 输入框
        self.entries = {}
        fields = ['标题', '作者', '出版社', 'ISBN']
        for i, field in enumerate(fields):
            label = ttk.Label(self, text=field, background='#EAEAEA')
            label.grid(row=i, column=0, padx=5, pady=5, sticky=tk.W)
            entry = ttk.Entry(self)
            entry.grid(row=i, column=1, padx=5, pady=5)
            self.entries[field] = entry

        search_button = ttk.Button(self, text="查询", command=self.perform_search)
        search_button.grid(row=len(fields), columnspan=2, pady=10)

    def perform_search(self):
        """执行查询"""
        conditions = []
        parameters = []

        for key, entry in self.entries.items():
            value = entry.get().strip()
            if value:
                column_name = {'标题': 'title', '作者': 'author', '出版社': 'publisher', 'ISBN': 'isbn'}[key]
                conditions.append(f"{column_name} LIKE ?")
                parameters.append(f"%{value}%")

        query = "SELECT * FROM Books"
        if conditions:
            query += " WHERE " + " AND ".join(conditions)

        with get_db_connection() as conn:
            cursor = conn.cursor()
            cursor.execute(query, parameters)
            rows = cursor.fetchall()

        self.master.load_books(rows)  # 使用自定义加载方法来显示查询结果
        self.destroy()

步骤 5: 启动应用程序

最后,在脚本的底部添加如下代码以启动应用程序:

if __name__ == '__main__':
    app = BookManagerApp()
    app.mainloop()

完整代码

import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import sqlite3
from pathlib import Path

# 数据库初始化函数
def init_db():
    """初始化数据库表结构"""
    with get_db_connection() as conn:
        cursor = conn.cursor()
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS Books (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                title TEXT NOT NULL,
                author TEXT NOT NULL,
                publisher TEXT,
                isbn TEXT UNIQUE,
                stock INTEGER DEFAULT 0
            )
        ''')
        conn.commit()

def get_db_connection():
    """获取数据库连接"""
    conn = sqlite3.connect(Path(__file__).parent / 'Library.db')
    conn.row_factory = sqlite3.Row
    return conn

class BookManagerApp(tk.Tk):
    """主应用程序类"""

    def __init__(self):
        super().__init__()
        self.title("图书管理系统")
        self.geometry("800x600")
        self.configure(bg='#EAEAEA')  # 设置背景颜色

        # 初始化数据库
        init_db()

        # 创建顶部菜单栏
        menubar = tk.Menu(self)
        file_menu = tk.Menu(menubar, tearoff=0)
        file_menu.add_command(label="退出", command=self.quit)
        menubar.add_cascade(label="文件", menu=file_menu)

        book_menu = tk.Menu(menubar, tearoff=0)
        book_menu.add_command(label="添加图书", command=self.open_add_book_window)
        book_menu.add_command(label="编辑图书", command=self.edit_selected_book)
        book_menu.add_command(label="删除图书", command=self.delete_selected_books)
        menubar.add_cascade(label="图书", menu=book_menu)

        self.config(menu=menubar)

        # 创建工具栏
        toolbar = ttk.Frame(self, style='TFrame')
        add_button = ttk.Button(toolbar, text="添加", command=self.open_add_book_window, style='TButton')
        edit_button = ttk.Button(toolbar, text="编辑", command=self.edit_selected_book, style='TButton')
        delete_button = ttk.Button(toolbar, text="删除", command=self.delete_selected_books, style='TButton')
        add_button.pack(side=tk.LEFT, padx=5, pady=5)
        edit_button.pack(side=tk.LEFT, padx=5, pady=5)
        delete_button.pack(side=tk.LEFT, padx=5, pady=5)
        toolbar.pack(side=tk.TOP, fill=tk.X)

        # 样式配置
        style = ttk.Style()
        style.theme_use('clam')  # 使用预定义的主题
        style.configure('TFrame', background='#EAEAEA')
        style.configure('TButton', font=('Arial', 12), foreground='black', background='#4CAF50')
        style.map('TButton', foreground=[('active', 'white')],
                  background=[('active', '#45a049')])
        style.configure('Treeview', font=('Arial', 12), rowheight=25)
        style.configure('Treeview.Heading', font=('Arial', 12, 'bold'))

        # 创建图书列表视图
        columns = ('id', 'title', 'author', 'publisher', 'isbn', 'stock')
        self.book_tree = ttk.Treeview(self, columns=columns, show='headings', style='Treeview')
        for col in columns:
            self.book_tree.heading(col, text=col.capitalize())
            self.book_tree.column(col, width=120, anchor=tk.CENTER)
        self.book_tree.pack(expand=True, fill=tk.BOTH, padx=10, pady=10)

        self.load_books()

    def load_books(self):
        """从数据库加载所有图书到列表视图"""
        for i in self.book_tree.get_children():
            self.book_tree.delete(i)

        with get_db_connection() as conn:
            cursor = conn.cursor()
            cursor.execute('SELECT * FROM Books')
            rows = cursor.fetchall()
            for row in rows:
                book_data = [row['id'], row['title'], row['author'], row['publisher'], row['isbn'], row['stock']]
                self.book_tree.insert('', tk.END, values=book_data)

    def open_add_book_window(self):
        """打开添加新书窗口"""
        AddBookWindow(self)

    def edit_selected_book(self):
        """编辑选中的图书记录"""
        selected_item = self.book_tree.selection()
        if not selected_item:
            messagebox.showwarning("警告", "请选择要编辑的图书!")
            return

        item_id = self.book_tree.item(selected_item)['values'][0]
        EditBookWindow(self, item_id)

    def delete_selected_books(self):
        """删除选中的图书记录"""
        selected_items = self.book_tree.selection()
        if not selected_items:
            messagebox.showwarning("警告", "请选择要删除的图书!")
            return

        confirm = messagebox.askyesno("确认删除", "确定要删除这些图书吗?")
        if not confirm:
            return

        book_ids = [self.book_tree.item(item)['values'][0] for item in selected_items]
        with get_db_connection() as conn:
            cursor = conn.cursor()
            cursor.executemany('DELETE FROM Books WHERE id=?', [(id,) for id in book_ids])
            conn.commit()

        for item in selected_items:
            self.book_tree.delete(item)


class AddBookWindow(tk.Toplevel):
    """添加新书窗口类"""

    def __init__(self, parent):
        super().__init__(parent)
        self.title("添加新书")
        self.geometry("400x300")
        self.configure(bg='#EAEAEA')

        # 输入框
        self.entries = {}
        fields = ['标题', '作者', '出版社', 'ISBN', '库存']
        for i, field in enumerate(fields):
            label = ttk.Label(self, text=field, background='#EAEAEA')
            label.grid(row=i, column=0, padx=5, pady=5, sticky=tk.W)
            entry = ttk.Entry(self)
            entry.grid(row=i, column=1, padx=5, pady=5)
            self.entries[field] = entry

        save_button = ttk.Button(self, text="保存", command=self.save_book)
        save_button.grid(row=len(fields), columnspan=2, pady=10)

    def save_book(self):
        """保存新书信息至数据库"""
        data = {key: entry.get() for key, entry in self.entries.items()}
        try:
            with get_db_connection() as conn:
                cursor = conn.cursor()
                cursor.execute('''
                    INSERT INTO Books (title, author, publisher, isbn, stock)
                    VALUES (?, ?, ?, ?, ?)
                ''', (data['标题'], data['作者'], data['出版社'], data['ISBN'], int(data['库存'])))
                conn.commit()
            self.destroy()
            self.master.load_books()
        except Exception as e:
            messagebox.showerror("错误", str(e))


class EditBookWindow(tk.Toplevel):
    """编辑图书窗口类"""

    def __init__(self, parent, book_id):
        super().__init__(parent)
        self.title("编辑图书")
        self.geometry("400x300")
        self.configure(bg='#EAEAEA')

        self.book_id = book_id
        self.entries = {}
        fields_mapping = {
            '标题': 'title',
            '作者': 'author',
            '出版社': 'publisher',
            'ISBN': 'isbn',
            '库存': 'stock'
        }

        # 从数据库获取要编辑的图书信息
        with get_db_connection() as conn:
            cursor = conn.cursor()
            cursor.execute('SELECT * FROM Books WHERE id=?', (book_id,))
            book = cursor.fetchone()

        if not book:
            messagebox.showerror("错误", "找不到指定ID的图书!")
            self.destroy()
            return

        # 打印列名以供调试
        print("Column names:", [description[0] for description in cursor.description])

        # 预填充表单字段
        for i, field in enumerate(fields_mapping.keys()):
            label = ttk.Label(self, text=field, background='#EAEAEA')
            label.grid(row=i, column=0, padx=5, pady=5, sticky=tk.W)
            entry = ttk.Entry(self)

            # 使用映射后的列名访问数据
            entry.insert(0, book[fields_mapping[field]])  # 使用映射后的列名

            entry.grid(row=i, column=1, padx=5, pady=5)
            self.entries[field] = entry

        save_button = ttk.Button(self, text="保存", command=self.update_book)
        save_button.grid(row=len(fields_mapping), columnspan=2, pady=10)

    def update_book(self):
        """更新图书信息至数据库"""
        data = {key: entry.get() for key, entry in self.entries.items()}
        try:
            with get_db_connection() as conn:
                cursor = conn.cursor()
                cursor.execute('''
                    UPDATE Books SET title=?, author=?, publisher=?, isbn=?, stock=?
                    WHERE id=?
                ''', (data['标题'], data['作者'], data['出版社'], data['ISBN'], int(data['库存']), self.book_id))
                conn.commit()
            self.destroy()
            self.master.load_books()  # 刷新主界面中的图书列表
        except Exception as e:
            messagebox.showerror("错误", str(e))

if __name__ == '__main__':
    app = BookManagerApp()
    app.mainloop()

标签:__,管理系统,python,self,cursor,book,conn,图书,tk
From: https://blog.csdn.net/qq491735628/article/details/145243466

相关文章

  • SSM在线仓储管理系统-毕业设计源码96366
    摘要本文介绍了一个基于SSM框架的在线仓储管理系统的设计与实现。该系统旨在提供一个便捷、高效的仓储管理平台,帮助企业实现对库存、出入库等仓储操作的自动化管理。在线仓储管理系统具有以下主要功能:用户登录与权限控制、库存管理、出入库管理、订单管理等。通过该系统,企......
  • node.js基于的图书书目推荐系统程序+论文 可用于毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容选题背景关于图书书目推荐系统的研究,现有研究主要以传统推荐算法在图书推荐中的应用为主,例如基于内容的推荐、基于协同过滤的推荐等。这些研究成果在一定程度上提高......
  • node.js基于的儿童手工创意店管理系统程序+论文 可用于毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于店铺管理系统的研究,现有研究主要以传统零售店铺或大型商业机构为主,专门针对儿童手工创意店的研究较少。在国内外,大多数店铺管理系统侧重于通用功能......
  • 【华为OD-E卷 - 最长连续子序列 100分(python、java、c++、js、c)】
    【华为OD-E卷-最长连续子序列100分(python、java、c++、js、c)】题目有N个正整数组成的一个序列。给定整数sum,求长度最长的连续子序列,使他们的和等于sum,返回此子序列的长度,如果没有满足要求的序列,返回-1输入描述第一行输入是:N个正整数组成的一个序列第二行输入是:给定......
  • 【华为OD-E卷 - 找出两个整数数组中同时出现的整数 100分(python、java、c++、js、c)】
    【华为OD-E卷-找出两个整数数组中同时出现的整数100分(python、java、c++、js、c)】题目现有两个整数数组,需要你找出两个数组中同时出现的整数,并按照如下要求输出:有同时出现的整数时,先按照同时出现次数(整数在两个数组中都出现并目出现次数较少的那个)进行归类,然后按照出......
  • 【华为OD-E卷 - 计算疫情扩散时间 100分(python、java、c++、js、c)】
    【华为OD-E卷-计算疫情扩散时间100分(python、java、c++、js、c)】题目在一个地图中(地图由n*n个区域组成),有部分区域被感染病菌。感染区域每天都会把周围(上下左右)的4个区域感染。请根据给定的地图计算,多少天以后,全部区域都会被感染。如果初始地图上所有区域全部都被感......
  • Python 项目和Pytorch 项目的环境构建
    python项目环境搭建首先下载软件包,打开安装创建项目:点击主菜单新建项目位置+pythonProject1构建python环境condecreate–p.envpython=3.10解释器:文件设置解释器本地解释器现有调试运行pytorch项目环境搭建先检查版本pip--version首先下载anaconda安装包这里......
  • 计算机毕业设计Springboot洗衣店管理系统 基于SpringBoot的智能洗衣店管理系统 洗衣店
    计算机毕业设计Springboot洗衣店管理系统74t7o5qc(配套有源码程序mysql数据库论文)本套源码可以先看具体功能演示视频领取,文末有联xi可分享随着人们生活水平的提高和时间成本的增加,越来越多的人选择将洗衣服务外包给洗衣店。洗衣店行业逐渐发展壮大,但同时也面临着管理难题......
  • 计算机毕业设计Springboot基于的游戏后台管理系统 基于Springboot的游戏后台运营管理
    计算机毕业设计Springboot基于的游戏后台管理系统a803t(配套有源码程序mysql数据库论文)本套源码可以先看具体功能演示视频领取,文末有联xi可分享随着游戏产业的蓬勃发展,游戏公司面临着海量用户数据、复杂的游戏内容以及多样化的运营活动管理挑战。传统的后台管理方式因人工......
  • 计算机毕业设计Springboot房屋租赁管理系统 基于SpringBoot的住宅租赁平台开发 Spring
    计算机毕业设计Springboot房屋租赁管理系统v26r4k2k(配套有源码程序mysql数据库论文)本套源码可以先看具体功能演示视频领取,文末有联xi可分享随着城市化进程的加速,房屋租赁市场日益繁荣,但同时也面临着诸多管理难题,如信息不对称、流程繁琐等。为了提升租赁市场的运营效率和......