????????寫一個小例子練習一下python語言。一個基于Python的校園書店管理系統,使用了tkinter庫構建圖形用戶界面(GUI),sqlite3?進行數據庫管理,matplotlib用于統計分析可視化。系統支持用戶登錄、書籍管理、客戶管理、員工管理、采購管理、銷售管理、統計分析和系統設置等功能。
一、運行環境
該系統是一個使用Python和Tkinter構建的校園書店管理系統,運行該程序需要以下環境:
(一)Python版本
使用Python 3.x版本,建議使用最新版,當前使用的是3.12版,python官網:www.python.org。因為我們在代碼中要使用到Python 3的語法和標準庫特性。例如,代碼中需要使用os.path.join等Python 3支持的路徑處理方式。
(二)第三方庫
程序中使用了一些第三方庫,需要提前安裝:
1.tkinter
這是Python的標準GUI庫,用于創建圖形用戶界面。在大多數Python 3安裝中,tkinter?已經默認包含,無需額外安裝。
2.sqlite3
這是Python的標準數據庫接口,用于操作SQLite數據庫,同樣無需額外安裝。但是數據庫管理工具SQLite-Web需要安裝。
SQLite-Web是一個基于Web瀏覽器的輕量級SQLite數據庫管理工具。它基于Python開發,免費開源,無需復雜的安裝或配置,適合快速搭建本地或內網的SQLite管理和開發環境。SQLite-Web支持常見的SQLite數據庫管理和開發任務,包括:
- 管理和操作已有的SQLite數據庫,或者新建數據庫;
- 支持表、字段以及索引的創建、修改和刪除;
- 支持導入/導出CSV、JSON格式的數據文件;
- 支持數據的增刪改查操作;
- 支持書簽功能,保存常用腳本;
- 支持URL分享查詢語句;
- 提供常見SQL語句幫助。
SQLite-Web的安裝非常簡單,但是它的依賴項很多,如果是不先安裝依賴項,則SQLite-Web無法安裝成功,以下是安裝依賴項的命令如下:
pip install Flask Peewee Pygments
Python環境中使用pip進行SQLite-Web安裝的命令如下:
pip install sqlite-web
建好數據庫之后,就可以執行以下命令運行SQLite-Web,來管理數據庫了:
sqlite_web /path/to/database.db
這里最好指定絕對路徑。如:
sqlite_web C:/Users/lzm07/Desktop/BookstoreApp/bookstore.db
運行成功后在瀏覽器中輸入以下地址進行訪問:http://127.0.0.1:8080/
會在頁面顯示數據表的結構(Structure),包括字段、索引、觸發器以及外鍵;同時可以修改表的字段和索引等信息。
3.matplotlib
用于繪制統計圖表。可以使用以下命令進行安裝:
pip install matplotlib
(四)數據庫文件
程序使用SQLite數據庫bookstore.db來存儲數據,確保該數據庫文件存在于與BookstoreApp.py相同的目錄下。如果文件不存在,程序會自動創建所需的表結構,并添加默認的管理員賬戶,賬號密碼都是admin。
(五)字體支持
程序中設置了?matplotlib?支持中文顯示,需要系統中安裝有相應的中文字體,如?SimHei(黑體)。如果系統中沒有該字體,可能會導致中文顯示異常。
(六)運行步驟總結
(1)確保已經安裝了 Python 3.x 版本。
(2)使用?pip?安裝?matplotlib?庫。
(3)確保?config.ini?文件存在且格式正確(后面說明如何創建)。
(4)確保?bookstore.db?文件存在或程序可以創建該文件。
(5)CMD中運行?BookstoreApp.py?文件:
python BookstoreApp.py
通過以上步驟,你應該能夠成功運行該校園書店管理系統。
二、系統整體概述
接下來詳細說明如何構建整個系統,該系統使用了tkinter庫構建圖形用戶界面(GUI),sqlite3?進行數據庫管理,matplotlib用于統計分析可視化。系統支持用戶登錄、書籍管理、客戶管理、員工管理、采購管理、銷售管理、統計分析和系統設置等功能。
(一)代碼樹形結構
整個項目的代碼樹形結構如下:
BookstoreApp/
├── config.ini
├── bookstore.db(自動創建)
└── BookstoreApp.py
其中BookstoreApp是項目根目錄。里面包含了三個文件。
(二)程序組成部分
(1)配置文件模塊:config.ini?用于存儲系統的基本設置,如系統名稱、庫存警告值、每頁記錄數等。
(2)主程序模塊:BookstoreApp.py?包含了系統的主要業務邏輯和GUI界面。
(3)數據庫管理:使用?sqlite3?進行數據庫的連接、表的創建和數據的操作。
(4)用戶界面:使用?tkinter?庫創建登錄界面、主界面、導航欄和各個管理頁面。內容都包含在BookstoreApp.py文件中。
(5)統計分析:使用?matplotlib?進行數據可視化,目前代碼中未完整實現可視化部分,但預留了相關接口。內容都包含在BookstoreApp.py文件中。
系統的主要功能包括:
- 用戶登錄與權限控制
- 書籍信息的增刪改查
- 客戶信息的管理
- 員工信息的管理
- 采購流程的管理
- 銷售流程的管理
- 數據統計與分析
- 系統設置與數據庫備份恢復
(三)BookstoreApp.py簡要說明
1.BookstoreApp.py文件樹形結構
BookstoreApp.py
├── 導入模塊
│ ??├── tkinter 及其子模塊
│ ??├── sqlite3
│ ??├── datetime
│ ??├── os
│ ??├── matplotlib 及其子模塊
│ ??├── configparser
├── 全局配置
│ ??├── 讀取配置文件 config.ini
│ ??├── 設置 matplotlib 中文字體
├── BookstoreApp 類
│ ??├── __init__(self, root)
│ ??├── load_config(self)
│ ??├── save_config(self)
│ ??├── create_tables(self)
│ ??├── create_main_window(self)
│ ??├── create_navbar(self)
│ ??├── show_login_page(self)
│ ??│ ??└── login(self)
│ ??├── setup_navigation(self)
│ ??├── show_welcome_page(self)
│ ??├── show_book_management(self)
│ ??│ ??├── search_books(self)
│ ??│ ??├── open_add_book_dialog(self)
│ ??│ ??│ ??└── add_book(self)
│ ??│ ??├── open_edit_book_dialog(self)
│ ??│ ??│ ??└── update_book(self)
│ ??│ ??└── delete_book(self)
│ ??├── load_books(self, keyword="")
│ ??├── show_customer_management(self)
│ ??│ ??├── search_customers(self)
│ ??│ ??├── open_add_customer_dialog(self)
│ ??│ ??│ ??└── add_customer(self)
│ ??│ ??├── open_edit_customer_dialog(self)
│ ??│ ??│ ??└── update_customer(self)
│ ??│ ??└── delete_customer(self)
│ ??├── load_customers(self, keyword="")
│ ??├── show_employee_management(self)
│ ??│ ??├── search_employees(self)
│ ??│ ??├── open_add_employee_dialog(self)
│ ??│ ??│ ??└── add_employee(self)
│ ??│ ??├── open_edit_employee_dialog(self)
│ ??│ ??│ ??└── update_employee(self)
│ ??│ ??└── delete_employee(self)
│ ??├── load_employees(self, keyword="")
│ ??├── show_purchase_management(self)
│ ??├── show_sale_management(self)
│ ??├── show_statistics(self)
│ ??└── show_system_settings(self)
└── 主程序入口
????└── if __name__ == "__main__":
2.各方法主要功能說明
(1)類外部分
1導入模塊
- 導入tkinter及其子模塊用于GUI開發
- 導入sqlite3用于數據庫操作
- 導入datetime用于日期處理
- 導入os用于文件路徑操作
- 導入matplotlib及其子模塊用于數據可視化
- 導入configparser用于讀取配置文件
2全局配置
- 讀取config.ini文件獲取系統名稱、庫存警告值等配置
- 設置matplotlib支持中文顯示
(2)BookstoreApp類方法
1初始化與配置
- __init__(self, root):初始化應用程序,設置窗口屬性,連接數據庫,創建主界面
- load_config(self):從配置文件讀取系統設置
- save_config(self):將當前設置保存到配置文件
- create_tables(self):創建數據庫表結構(書籍、客戶、員工、采購、銷售、用戶)
2界面構建
- create_main_window(self):創建主窗口框架
- create_navbar(self):創建頂部導航欄
- setup_navigation(self):根據用戶角色設置導航項
3用戶認證
- show_login_page(self):顯示登錄頁面
- login(self):處理用戶登錄驗證
4主頁面與功能模塊
- show_welcome_page(self):顯示歡迎頁面,展示系統概覽和最近銷售記錄
- show_book_management(self):顯示書籍管理頁面,支持搜索、添加、編輯、刪除書籍
- show_customer_management(self):顯示客戶管理頁面,支持客戶信息管理
- show_employee_management(self):顯示員工管理頁面(管理員權限)
- show_purchase_management(self):顯示采購管理頁面
- show_sale_management(self):顯示銷售管理頁面
- show_statistics(self):顯示統計分析頁面
- show_system_settings(self):顯示系統設置頁面
5數據加載與操作
- load_books(self, keyword):加載書籍數據,支持關鍵詞搜索
- load_customers(self, keyword):加載客戶數據,支持關鍵詞搜索
- load_employees(self, keyword):加載員工數據,支持關鍵詞搜索
6對話框與操作
- open_add_book_dialog(self):打開添加書籍對話框
- add_book(self):執行添加書籍操作
- open_edit_book_dialog(self):打開編輯書籍對話框
- update_book(self):執行更新書籍操作
- delete_book(self):執行刪除書籍操作
- 類似的客戶和員工管理方法:open_add_customer_dialog、update_customer、delete_customer 等
3.方法功能總結
這個書店管理系統采用了典型的MVC(模型 - 視圖 - 控制器)架構:
- 模型層:通過sqlite3操作數據庫表
- 視圖層:使用tkinter創建各種GUI界面
- 控制層:通過類方法處理用戶交互和業務邏輯
系統實現了完整的CRUD(創建、讀取、更新、刪除)操作,支持用戶認證、多角色權限管理、數據統計和系統配置等功能。配置文件和數據庫均采用UTF-8編碼,確保中文顯示正常。
三、系統代碼詳細說明
(一)config.ini文件
程序依賴于config.ini文件來讀取系統配置信息,確保該文件存在于與BookstoreApp.py相同的目錄下,并且文件內容格式正確。這個地方要求文件后綴是ini文件,文件編碼一定是utf-8編碼方式,否則系統運行出錯。
[settings]system_name = bobo校園書店管理系統stock_warning_value = 10records_per_page = 20
在代碼開發工具中創建好文件保存后,可以通過用“記事本”打開,再“另存為”的方式修改編碼方式。
(1)原理:INI文件是一種常見的配置文件格式,由多個節(section)組成,每個節包含多個鍵值對(key-value pair)。[settings]?是節的名稱,下面的system_name、stock_warning_value和records_per_page是鍵,對應的值分別是系統名稱、庫存警告值和每頁記錄數。
(2)所需依賴包:無,Python 標準庫中的?configparser?模塊可用于讀取和寫入 INI 文件。
(3)運行環境:ini是文本文件,不依賴特定運行環境。
(二)BookstoreApp.py文件
BookstoreApp.py?包含了系統的主要業務邏輯和GUI界面,是整個程序的主模塊。
1.導入依賴包
程序需要多個依賴包,所在在程序開頭,先導入python的依賴包。
import tkinter as tkfrom tkinter import ttk, messageboximport sqlite3import datetimeimport osimport matplotlib.pyplot as pltfrom matplotlib.backends.backend_tkagg import FigureCanvasTkAggfrom tkinter import filedialogimport configparser
原理說明:導入所需的Python庫和模塊,tkinter用于創建GUI,sqlite3用于數據庫操作,datetime用于處理日期時間,os用于操作系統相關操作,matplotlib用于數據可視化,configparser用于讀取和寫入配置文件。
2.讀取配置文件
要實現全局調用保存好的系統名稱、庫存預警值和每頁顯示記錄數,我們可以將這些配置信息存儲在一個配置文件中,然后在代碼里全局引用這些配置。為了持久化配置信息,本系統使用了ini文件來存儲配置信息,自然在加載程序之前,就要先加載配置信息,因此,在導入依賴包之后,就開始讀取配置文件。
# 讀取配置文件,使用絕對路徑config = configparser.ConfigParser()config_file_path = os.path.join(os.path.dirname(__file__), 'config.ini')# 指定編碼為 UTF-8 讀取配置文件config.read(config_file_path, encoding='utf-8')try:# 獲取配置信息system_name = config.get('settings', 'system_name')stock_warning_value = int(config.get('settings', 'stock_warning_value'))records_per_page = int(config.get('settings', 'records_per_page'))except configparser.NoSectionError:messagebox.showerror("配置文件錯誤", "未找到 'settings' 節,請檢查配置文件。")raise
(1)原理:使用configparser?模塊讀取?config.ini文件中的配置信息。如果配置文件中缺少settings節,會彈出錯誤消息框。
(2)所需依賴包:configparser(Python標準庫)。
(3)配置文件路徑問題
- 程序是在當前工作目錄下讀取config.ini文件,要是當前工作目錄并非BookstoreApp所在目錄,就會找不到該文件。
- 使用絕對路徑讀取配置文件:借助os.path.join(os.path.dirname(__file__), 'config.ini')來獲取配置文件的絕對路徑。os.path.dirname(__file__)這個讀取的是BookstoreApp.py所在的目錄。
- 添加異常處理:運用try-except語句捕獲configparser.NoSectionError異常,并且彈出錯誤提示框。
通過這些修改,程序就能準確讀取配置文件,避免因路徑問題而引發的錯誤。
(4)config.ini文件中文顯示亂碼的問題
config.ini文件中文顯示亂碼通常是由于文件編碼問題導致的。在讀取和寫入配置文件時,需要指定正確的編碼格式,一般使用UTF-8編碼。
- 讀取配置文件:在 config.read方法中指定encoding='utf-8'來讀取配置文件。
- 保存配置文件:在open函數中指定encoding='utf-8'來寫入配置文件。
- 這也要求配置文件config.ini是UTF-8編碼的。
3.設置matplotlib支持中文顯示
由于在系統中添加了圖形可視化,而圖形中有很多中文字符,所以需要支持中文。在讀取配置文件之后添加以下代碼:
plt.rcParams["font.family"] = ["SimHei"]plt.rcParams["axes.unicode_minus"] = False???# 解決負號顯示問題
(1)原理:設置?matplotlib?的字體為黑體,解決中文顯示問題,同時解決負號顯示問題。
(2)所需依賴包:matplotlib。
4.BookstoreApp類
BookstoreApp?類是系統的核心類,__init__?方法用于初始化系統,包括創建主窗口、加載配置文件、連接數據庫、創建數據庫表和顯示登錄頁面。
class BookstoreApp:def __init__(self, root):self.root = root# 讀取配置文件self.config_file = os.path.join(os.path.dirname(__file__), 'config.ini')self.load_config()self.root.title(f"{system_name}")self.root.geometry("1024x768")self.root.minsize(800, 600)# 數據庫連接self.db_path = os.path.join(os.path.dirname(__file__), "bookstore.db") # 構建數據庫的絕對路徑# 使用絕對路徑連接數據庫self.conn = sqlite3.connect(self.db_path)self.create_tables()# 當前用戶信息self.current_user = None# 創建主界面self.create_main_window()
所需依賴包:tkinter、sqlite3、configparser。
5.load_config方法
要實現將“系統設置”保存到config.ini并全局應用,就需要先實現對配置文件內容的加載和保存,并在程序啟動時檢查并創建配置文件。load_config方法用于加載配置,save_config方法用于保存配置。
def load_config(self):try:config = configparser.ConfigParser()# 指定編碼為 UTF-8 讀取配置文件config.read(self.config_file, encoding='utf-8')self.system_name = config.get('settings', 'system_name', fallback="bobo校園書店管理系統")self.stock_warning_value = int(config.get('settings', 'stock_warning_value', fallback=10))self.records_per_page = int(config.get('settings', 'records_per_page', fallback=20))self.root.title(self.system_name) # 設置窗口標題except Exception as e:messagebox.showerror("配置錯誤", f"加載配置失敗: {str(e)}")# 使用默認值self.system_name = "bobo校園書店管理系統"self.stock_warning_value = 10self.records_per_page = 20
(1)代碼說明:讀取配置文件中的配置信息,如果讀取失敗,使用默認值。
(2)所需依賴包:configparser、tkinter。
需要涉及到的關鍵部分包括:
- 配置文件管理:添加load_config和save_config方法
- 系統設置保存:更新show_system_settings中的保存邏輯
- 系統標題:在load_config中設置窗口標題
- 分頁功能:在所有列表頁面使用self.records_per_page
- 庫存預警:在統計分析中使用self.stock_warning_value
- 配置文件初始化:在創建表時檢查并創建配置文件
這些修改將確保系統設置能夠正確保存到配置文件,并在整個系統中全局應用。
6.save_config方法
將當前的配置信息寫入?config.ini?文件。
def save_config(self):config = configparser.ConfigParser()config['settings'] = {'system_name': self.system_name,'stock_warning_value': self.stock_warning_value,'records_per_page': self.records_per_page}try:# 指定編碼為 UTF-8 寫入配置文件with open(self.config_file, 'w', encoding='utf-8') as f:config.write(f)messagebox.showinfo("成功", "配置已保存!")except Exception as e:messagebox.showerror("錯誤", f"保存配置失敗: {str(e)}")
7.create_tables方法
在設計之初,希望減輕用戶的開發難度,省略數據庫的設計。所以你可以直接運行這個程序來使用校園書店管理系統,首次運行會自動創建數據庫并添加默認管理員賬戶(用戶名:admin,密碼:admin)。自動創建數據庫并添加默認管理員賬戶的功能就由create_tables方法實現。
def create_tables(self):# 檢查配置文件是否存在,不存在則創建if not os.path.exists(self.config_file):self.save_config()# 創建書籍表self.conn.execute('''CREATE TABLE IF NOT EXISTS books (isbn TEXT PRIMARY KEY,title TEXT NOT NULL,author TEXT,publisher TEXT,price REAL,stock INTEGER)''')# 創建客戶表self.conn.execute('''CREATE TABLE IF NOT EXISTS customers (customer_id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT NOT NULL,contact TEXT,membership TEXT DEFAULT '普通會員',points INTEGER DEFAULT 0)''')# 創建員工表self.conn.execute('''CREATE TABLE IF NOT EXISTS employees (employee_id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT NOT NULL,position TEXT,salary REAL,hire_date TEXT)''')# 創建采購表self.conn.execute('''CREATE TABLE IF NOT EXISTS purchases (purchase_id INTEGER PRIMARY KEY AUTOINCREMENT,isbn TEXT NOT NULL,quantity INTEGER NOT NULL,price REAL NOT NULL,supplier TEXT,purchase_date TEXT,FOREIGN KEY (isbn) REFERENCES books(isbn))''')# 創建銷售表self.conn.execute('''CREATE TABLE IF NOT EXISTS sales (sale_id INTEGER PRIMARY KEY AUTOINCREMENT,isbn TEXT NOT NULL,customer_id INTEGER,quantity INTEGER NOT NULL,price REAL NOT NULL,sale_date TEXT,FOREIGN KEY (isbn) REFERENCES books(isbn),FOREIGN KEY (customer_id) REFERENCES customers(customer_id))''')# 創建用戶表(用于登錄)self.conn.execute('''CREATE TABLE IF NOT EXISTS users (username TEXT PRIMARY KEY,password TEXT NOT NULL,role TEXT NOT NULL,employee_id INTEGER,FOREIGN KEY (employee_id) REFERENCES employees(employee_id))''')# 添加默認管理員賬戶(如果不存在)cursor = self.conn.cursor()cursor.execute("SELECT COUNT(*) FROM users WHERE username = 'admin'")if cursor.fetchone()[0] == 0:self.conn.execute("INSERT INTO users (username, password, role) VALUES ('admin', 'admin', '管理員')")self.conn.commit()self.conn.commit()
(1)代碼說明:檢查配置文件是否存在,如果不存在則保存默認配置。創建數據庫中的各個表,包括書籍表、客戶表、員工表、采購表、銷售表和用戶表。如果表已經存在,則不進行創建。添加默認管理員賬戶(如果不存在)。
(2)所需依賴包:sqlite3、os。
當創建好數據庫之后,可以按前文方法瀏覽器打開SQLite-Web數據庫管理工具,可以看到如下界面:
8.create_main_window方法
create_main_window方法創建程序主窗口的方法,創建窗口之后,創建頂部導航欄和主框架,初始顯示登錄頁面。
def create_main_window(self):# 創建頂部導航欄self.create_navbar()# 創建主框架self.main_frame = ttk.Frame(self.root)self.main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)# 初始顯示登錄頁面self.show_login_page()
所需依賴包:tkinter。
運行代碼之后的,首先調用show_login_page()方法,顯示登錄界面,效果如下:
9.create_navbar方法
在create_main_window方法中要創建頂部導航欄。
def create_navbar(self):# 頂部導航欄self.navbar = ttk.Frame(self.root, height=40)self.navbar.pack(fill=tk.X)# 品牌標識self.brand_label = ttk.Label(self.navbar, text=f"{system_name}", font=("微軟雅黑", 12, "bold"))self.brand_label.pack(side=tk.LEFT, padx=10, pady=10)# 導航按鈕(初始隱藏,登錄后顯示)self.nav_buttons = {}self.nav_frame = ttk.Frame(self.navbar)# 狀態標簽self.status_label = ttk.Label(self.navbar, text="未登錄", font=("微軟雅黑", 10))self.status_label.pack(side=tk.RIGHT, padx=10, pady=10)
創建頂部導航欄,包括品牌標識、導航按鈕(初始隱藏)和狀態標簽。
當登錄主界面之后,看到的效果如下:
10.show_login_page方法
show_login_page方法,用于顯示登錄頁面,包括用戶名和密碼輸入框、登錄按鈕。用戶輸入用戶名和密碼后,點擊登錄按鈕或按下回車鍵,系統會在數據庫中查詢用戶信息,如果匹配則登錄成功,顯示歡迎頁面并設置導航欄;否則彈出登錄失敗的消息框。
def show_login_page(self):# 清空主框架for widget in self.main_frame.winfo_children():widget.destroy()# 隱藏導航按鈕if hasattr(self, 'nav_frame'):self.nav_frame.pack_forget()# 登錄框架login_frame = ttk.LabelFrame(self.main_frame, text="用戶登錄", padding=(20, 10))login_frame.pack(fill=tk.BOTH, expand=True, padx=200, pady=100, anchor=tk.CENTER)# 用戶名username_label = ttk.Label(login_frame, text="用戶名:")username_label.pack(pady=10, anchor=tk.CENTER)username_entry = ttk.Entry(login_frame, width=30)username_entry.pack(pady=5, anchor=tk.CENTER)# 密碼password_label = ttk.Label(login_frame, text="密碼:")password_label.pack(pady=10, anchor=tk.CENTER)password_entry = ttk.Entry(login_frame, width=30, show="*")password_entry.pack(pady=5, anchor=tk.CENTER)# 登錄按鈕def login():username = username_entry.get()password = password_entry.get()cursor = self.conn.cursor()cursor.execute("SELECT * FROM users WHERE username = ? AND password = ?", (username, password))user = cursor.fetchone()if user:self.current_user = {'username': user[0],'role': user[2]}self.status_label.config(text=f"當前用戶: {username} ({user[2]})")messagebox.showinfo("登錄成功", f"歡迎回來,{username}!")self.show_welcome_page()self.setup_navigation()else:messagebox.showerror("登錄失敗", "用戶名或密碼錯誤")login_button = ttk.Button(login_frame, text="登錄", command=login)login_button.pack(pady=20, anchor=tk.CENTER)# 綁定回車事件到登錄按鈕username_entry.bind("<Return>", lambda event: login())password_entry.bind("<Return>", lambda event: login())# 設置焦點username_entry.focus()
show_login_page方法方法中又嵌套了login()方法。
11.setup_navigation方法
系統劃分了兩個角色,分別是管理員和普通員工。根據用戶角色顯示不同的導航項,管理員可以訪問所有功能,普通員工只能訪問部分功能。添加退出登錄按鈕,點擊后返回登錄頁面。
def setup_navigation(self):# 清空現有導航按鈕for widget in self.nav_frame.winfo_children():widget.destroy()# 根據用戶角色顯示不同的導航項if self.current_user['role'] == '管理員':nav_items = [("首頁", self.show_welcome_page),("書籍管理", self.show_book_management),("客戶管理", self.show_customer_management),("員工管理", self.show_employee_management),("采購管理", self.show_purchase_management),("銷售管理", self.show_sale_management),("統計分析", self.show_statistics),("系統設置", self.show_system_settings)]else: # 普通員工nav_items = [("首頁", self.show_welcome_page),("書籍管理", self.show_book_management),("客戶管理", self.show_customer_management),("銷售管理", self.show_sale_management)]# 添加導航按鈕for text, command in nav_items:btn = ttk.Button(self.nav_frame, text=text, command=command)btn.pack(side=tk.LEFT, padx=5, pady=5)# 添加退出按鈕ttk.Button(self.nav_frame, text="退出登錄", command=self.show_login_page).pack(side=tk.RIGHT, padx=5, pady=5)# 顯示導航框架self.nav_frame.pack(side=tk.LEFT, padx=10, pady=5)
管理員的界面效果如下:
當在管理員賬號下,添加了員工之后,可以使用員工的賬號密碼登錄,登錄的界面效果如下:
兩種角色可以管理的功能是不同的。
12.show_welcome_page方法
顯示歡迎頁面,包括系統概覽(書籍總數、客戶總數、今日銷售額、庫存預警)和最近銷售記錄。從數據庫中查詢相關數據并顯示在界面上。
def show_welcome_page(self):# 清空主框架for widget in self.main_frame.winfo_children():widget.destroy()# 創建歡迎界面welcome_label = ttk.Label(self.main_frame, text=f"歡迎使用{system_name}", font=("微軟雅黑", 24))welcome_label.pack(pady=50)# 顯示系統信息info_frame = ttk.LabelFrame(self.main_frame, text="系統概覽", padding=(10, 5))info_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)# 獲取統計數據cursor = self.conn.cursor()# 書籍總數cursor.execute("SELECT COUNT(*) FROM books")book_count = cursor.fetchone()[0]# 客戶總數cursor.execute("SELECT COUNT(*) FROM customers")customer_count = cursor.fetchone()[0]# 今日銷售額today = datetime.date.today().strftime("%Y-%m-%d")cursor.execute("SELECT SUM(price * quantity) FROM sales WHERE sale_date = ?", (today,))today_sales = cursor.fetchone()[0] or 0# 庫存預警cursor.execute(f"SELECT COUNT(*) FROM books WHERE stock < {self.stock_warning_value}")low_stock_count = cursor.fetchone()[0]# 顯示統計數據stats = [("書籍總數", book_count),("客戶總數", customer_count),("今日銷售額", f"¥{today_sales:.2f}"),("庫存預警", low_stock_count)]for i, (label, value) in enumerate(stats):frame = ttk.Frame(info_frame)frame.pack(fill=tk.X, padx=10, pady=5)ttk.Label(frame, text=label, font=("微軟雅黑", 12)).pack(side=tk.LEFT, padx=10)ttk.Label(frame, text=str(value), font=("微軟雅黑", 16, "bold")).pack(side=tk.RIGHT, padx=10)# 最近銷售記錄recent_frame = ttk.LabelFrame(self.main_frame, text="最近銷售記錄", padding=(10, 5))recent_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)# 創建表格columns = ("sale_id", "isbn", "title", "customer", "quantity", "price", "date")self.recent_tree = ttk.Treeview(recent_frame, columns=columns, show="headings", height=5)# 設置列標題self.recent_tree.heading("sale_id", text="銷售ID")self.recent_tree.heading("isbn", text="ISBN")self.recent_tree.heading("title", text="書名")self.recent_tree.heading("customer", text="客戶")self.recent_tree.heading("quantity", text="數量")self.recent_tree.heading("price", text="金額")self.recent_tree.heading("date", text="日期")# 設置列寬self.recent_tree.column("sale_id", width=80)self.recent_tree.column("isbn", width=120)self.recent_tree.column("title", width=200)self.recent_tree.column("customer", width=100)self.recent_tree.column("quantity", width=80)self.recent_tree.column("price", width=80)self.recent_tree.column("date", width=120)self.recent_tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)# 獲取最近10條銷售記錄cursor.execute('''SELECT s.sale_id, s.isbn, b.title, c.name, s.quantity, s.price, s.sale_dateFROM sales sLEFT JOIN books b ON s.isbn = b.isbnLEFT JOIN customers c ON s.customer_id = c.customer_idORDER BY s.sale_date DESCLIMIT 10''')for row in cursor.fetchall():self.recent_tree.insert("", tk.END, values=row)
所需依賴包:tkinter、sqlite3、datetime。
13.show_book_management方法
顯示書籍管理頁面,包括搜索框、添加書籍按鈕、書籍列表表格、編輯按鈕和刪除按鈕。用戶可以搜索書籍、添加新書籍、編輯現有書籍信息,以及操作之后對數據列表進行刷新。
def show_book_management(self):# 清空主框架for widget in self.main_frame.winfo_children():widget.destroy()# 創建管理界面manage_frame = ttk.LabelFrame(self.main_frame, text="書籍管理", padding=(10, 5))manage_frame.pack(fill=tk.BOTH, expand=True)# 上部操作區top_frame = ttk.Frame(manage_frame)top_frame.pack(fill=tk.X, padx=10, pady=10)# 搜索框ttk.Label(top_frame, text="搜索:").pack(side=tk.LEFT, padx=5)search_entry = ttk.Entry(top_frame, width=30)search_entry.pack(side=tk.LEFT, padx=5)def search_books():keyword = search_entry.get()self.load_books(keyword)ttk.Button(top_frame, text="搜索", command=search_books).pack(side=tk.LEFT, padx=5)# 添加按鈕def open_add_book_dialog():dialog = tk.Toplevel(self.root)dialog.title("添加書籍")dialog.geometry("500x400")dialog.resizable(True, True)dialog.transient(self.root)dialog.grab_set()# 表單框架form_frame = ttk.Frame(dialog, padding=(20, 10))form_frame.pack(fill=tk.BOTH, expand=True)# ISBNttk.Label(form_frame, text="ISBN:").grid(row=0, column=0, sticky=tk.W, pady=10)isbn_entry = ttk.Entry(form_frame, width=30)isbn_entry.grid(row=0, column=1, pady=10)# 書名ttk.Label(form_frame, text="書名:").grid(row=1, column=0, sticky=tk.W, pady=10)title_entry = ttk.Entry(form_frame, width=30)title_entry.grid(row=1, column=1, pady=10)# 作者ttk.Label(form_frame, text="作者:").grid(row=2, column=0, sticky=tk.W, pady=10)author_entry = ttk.Entry(form_frame, width=30)author_entry.grid(row=2, column=1, pady=10)# 出版社ttk.Label(form_frame, text="出版社:").grid(row=3, column=0, sticky=tk.W, pady=10)publisher_entry = ttk.Entry(form_frame, width=30)publisher_entry.grid(row=3, column=1, pady=10)# 價格ttk.Label(form_frame, text="價格:").grid(row=4, column=0, sticky=tk.W, pady=10)price_entry = ttk.Entry(form_frame, width=30)price_entry.grid(row=4, column=1, pady=10)# 庫存ttk.Label(form_frame, text="庫存:").grid(row=5, column=0, sticky=tk.W, pady=10)stock_entry = ttk.Entry(form_frame, width=30)stock_entry.grid(row=5, column=1, pady=10)# 添加按鈕def add_book():isbn = isbn_entry.get()title = title_entry.get()author = author_entry.get()publisher = publisher_entry.get()try:price = float(price_entry.get())stock = int(stock_entry.get())except ValueError:messagebox.showerror("錯誤", "價格和庫存必須是數字!")returnif not isbn or not title:messagebox.showerror("錯誤", "ISBN和書名不能為空!")returntry:self.conn.execute("INSERT INTO books VALUES (?, ?, ?, ?, ?, ?)",(isbn, title, author, publisher, price, stock))self.conn.commit()messagebox.showinfo("成功", "書籍添加成功!")dialog.destroy()self.load_books()except sqlite3.IntegrityError:messagebox.showerror("錯誤", "ISBN已存在!")except Exception as e:messagebox.showerror("錯誤", f"添加書籍失敗: {str(e)}")ttk.Button(form_frame, text="添加", command=add_book).grid(row=6, column=0, columnspan=2, pady=20)ttk.Button(top_frame, text="添加書籍", command=open_add_book_dialog).pack(side=tk.RIGHT, padx=5)# 表格區域table_frame = ttk.Frame(manage_frame)table_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)# 創建表格columns = ("isbn", "title", "author", "publisher", "price", "stock")self.book_tree = ttk.Treeview(table_frame, columns=columns, show="headings", height=self.records_per_page)# 設置列標題self.book_tree.heading("isbn", text="ISBN")self.book_tree.heading("title", text="書名")self.book_tree.heading("author", text="作者")self.book_tree.heading("publisher", text="出版社")self.book_tree.heading("price", text="價格")self.book_tree.heading("stock", text="庫存")# 設置列寬self.book_tree.column("isbn", width=150)self.book_tree.column("title", width=200)self.book_tree.column("author", width=150)self.book_tree.column("publisher", width=150)self.book_tree.column("price", width=80, anchor=tk.E)self.book_tree.column("stock", width=80, anchor=tk.E)self.book_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)# 添加滾動條scrollbar = ttk.Scrollbar(table_frame, orient=tk.VERTICAL, command=self.book_tree.yview)self.book_tree.configure(yscroll=scrollbar.set)scrollbar.pack(side=tk.RIGHT, fill=tk.Y)# 底部按鈕區域bottom_frame = ttk.Frame(manage_frame)bottom_frame.pack(fill=tk.X, padx=10, pady=10)# 編輯按鈕def open_edit_book_dialog():selected_item = self.book_tree.selection()if not selected_item:messagebox.showinfo("提示", "請先選擇一本書!")returnitem = self.book_tree.item(selected_item[0])values = item['values']dialog = tk.Toplevel(self.root)dialog.title("編輯書籍")dialog.geometry("500x400")dialog.resizable(True, True)dialog.transient(self.root)dialog.grab_set()# 表單框架form_frame = ttk.Frame(dialog, padding=(20, 10))form_frame.pack(fill=tk.BOTH, expand=True)# ISBN (只讀)ttk.Label(form_frame, text="ISBN:").grid(row=0, column=0, sticky=tk.W, pady=10)isbn_entry = ttk.Entry(form_frame, width=30)isbn_entry.grid(row=0, column=1, pady=10)isbn_entry.insert(0, values[0])isbn_entry.configure(state='readonly')# 書名ttk.Label(form_frame, text="書名:").grid(row=1, column=0, sticky=tk.W, pady=10)title_entry = ttk.Entry(form_frame, width=30)title_entry.grid(row=1, column=1, pady=10)title_entry.insert(0, values[1])# 作者ttk.Label(form_frame, text="作者:").grid(row=2, column=0, sticky=tk.W, pady=10)author_entry = ttk.Entry(form_frame, width=30)author_entry.grid(row=2, column=1, pady=10)author_entry.insert(0, values[2])# 出版社ttk.Label(form_frame, text="出版社:").grid(row=3, column=0, sticky=tk.W, pady=10)publisher_entry = ttk.Entry(form_frame, width=30)publisher_entry.grid(row=3, column=1, pady=10)publisher_entry.insert(0, values[3])# 價格ttk.Label(form_frame, text="價格:").grid(row=4, column=0, sticky=tk.W, pady=10)price_entry = ttk.Entry(form_frame, width=30)price_entry.grid(row=4, column=1, pady=10)price_entry.insert(0, values[4])# 庫存ttk.Label(form_frame, text="庫存:").grid(row=5, column=0, sticky=tk.W, pady=10)stock_entry = ttk.Entry(form_frame, width=30)stock_entry.grid(row=5, column=1, pady=10)stock_entry.insert(0, values[5])# 更新按鈕def update_book():isbn = isbn_entry.get()title = title_entry.get()author = author_entry.get()publisher = publisher_entry.get()try:price = float(price_entry.get())stock = int(stock_entry.get())except ValueError:messagebox.showerror("錯誤", "價格和庫存必須是數字!")returnif not isbn or not title:messagebox.showerror("錯誤", "ISBN和書名不能為空!")returntry:self.conn.execute("UPDATE books SET title=?, author=?, publisher=?, price=?, stock=? WHERE isbn=?",(title, author, publisher, price, stock, isbn))self.conn.commit()messagebox.showinfo("成功", "書籍更新成功!")dialog.destroy()self.load_books()except Exception as e:messagebox.showerror("錯誤", f"更新書籍失敗: {str(e)}")ttk.Button(form_frame, text="更新", command=update_book).grid(row=6, column=0, columnspan=2, pady=20)ttk.Button(bottom_frame, text="編輯", command=open_edit_book_dialog).pack(side=tk.LEFT, padx=5)# 刪除按鈕def delete_book():selected_item = self.book_tree.selection()if not selected_item:messagebox.showinfo("提示", "請先選擇一本書!")returnitem = self.book_tree.item(selected_item[0])isbn = item['values'][0]title = item['values'][1]if messagebox.askyesno("確認", f"確定要刪除《{title}》嗎?"):try:# 先檢查是否有銷售記錄cursor = self.conn.cursor()cursor.execute("SELECT COUNT(*) FROM sales WHERE isbn = ?", (isbn,))count = cursor.fetchone()[0]if count > 0:messagebox.showerror("錯誤", "該書存在銷售記錄,不能刪除!")returnself.conn.execute("DELETE FROM books WHERE isbn = ?", (isbn,))self.conn.commit()messagebox.showinfo("成功", "書籍刪除成功!")self.load_books()except Exception as e:messagebox.showerror("錯誤", f"刪除書籍失敗: {str(e)}")ttk.Button(bottom_frame, text="刪除", command=delete_book).pack(side=tk.LEFT, padx=5)# 刷新按鈕ttk.Button(bottom_frame, text="刷新", command=lambda: self.load_books()).pack(side=tk.RIGHT, padx=5)# 加載書籍數據self.load_books()
所需依賴包:tkinter、sqlite3。
書籍管理界面的效果如下:
14.load_books方法
show_book_management方法中,需要加載書籍數據,使用load_books方法。
def load_books(self, keyword=""):# 清空表格for item in self.book_tree.get_children():self.book_tree.delete(item)cursor = self.conn.cursor()if keyword:# 搜索查詢query = """SELECT isbn, title, author, publisher, price, stock FROM books WHERE isbn LIKE ? OR title LIKE ? OR author LIKE ?"""param = f"%{keyword}%"cursor.execute(query, (param, param, param))else:# 獲取所有書籍cursor.execute("SELECT isbn, title, author, publisher, price, stock FROM books")# 填充表格for row in cursor.fetchall():self.book_tree.insert("", tk.END, values=row)
15.show_customer_management方法
顯示客戶管理頁面,支持客戶信息管理。
load_customers()方法加載客戶列表。
添加客戶信息的界面如下:
16.show_employee_management方法
顯示員工管理頁面(管理員權限)
load_employees()方法加載員工列表
添加員工信息的界面如下:
17.show_purchase_management方法
顯示采購管理頁面
load_purchases()方法加載采購記錄列表
在添加采購記錄彈窗上,get_book_info()方法獲取書籍信息。
18.show_sale_management方法
顯示銷售管理頁面
load_sales()方法加載銷售記錄列表
在添加銷售記錄彈窗上,get_book_info()方法獲取書籍信息。get_customer_info()方法獲取客戶信息。
19.show_statistics方法
顯示統計分析頁面
update_statistics()方法用于當選擇新的參數時,更新統計數據。
20.show_system_settings方法
顯示系統設置頁面,包括了常規設置、數據庫設置、備份與恢復、用戶設置。
四、系統完整代碼
可以在我的CSDN博客上下載。地址:https://download.csdn.net/download/lzm12278828/91092825?
總結
該校園書店管理系統通過配置文件和數據庫實現了基本的書店管理功能,使用GUI界面提供了良好的用戶體驗。系統的主要依賴包為?tkinter、sqlite3?和?matplotlib,運行環境為 Python 3.x。