基于Python的畢業設計選題管理系統設計與實現
摘要
本論文詳細闡述了一個基于Python的畢業設計選題管理系統的設計與實現過程。該系統采用了Python的Tkinter庫構建圖形用戶界面,使用SQLite數據庫存儲數據,實現了高校畢業設計選題過程中的教師出題、學生選題、管理員協調等核心功能。系統通過角色權限管理確保數據安全性,采用模塊化設計提高代碼可維護性,最終通過測試驗證了系統的穩定性和實用性。該系統能夠有效提高選題管理效率,減少人工操作錯誤,為高校畢業設計管理提供了便捷的解決方案。
關鍵詞 Python;畢業設計管理;選題系統;Tkinter;SQLite
引言
- 研究背景與意義
畢業設計是高等教育人才培養過程中的重要環節,選題管理作為畢業設計的首要步驟,其效率和公平性直接影響到整個畢業設計的質量。傳統的選題管理方式主要依靠人工操作,存在流程繁瑣、信息不透明、容易出錯等問題。隨著計算機技術的發展,開發一套高效、便捷的畢業設計選題管理系統具有重要的現實意義。
- 國內外研究現狀
目前,國內外針對高校教學管理系統的研究已經取得了一定的成果,但專門針對畢業設計選題管理的系統還相對較少。國外一些高校管理系統功能較為全面,但往往價格昂貴且不符合國內高校的實際需求。國內相關系統在功能完整性、用戶體驗和系統擴展性方面仍存在不足。
- 研究目標與方法
本研究旨在開發一套適合國內高校使用的畢業設計選題管理系統,實現選題過程的自動化和信息化。研究方法采用需求分析、系統設計、編碼實現和測試驗證相結合的方式,確保系統滿足實際需求且具有良好的性能和可維護性。
系統需求分析
2.1 功能需求
用戶管理:支持管理員、教師和學生三種角色的注冊、登錄和權限管理。
選題管理:教師可以發布、修改和刪除選題;學生可以查看選題并提交選題申請;管理員可以審核選題。
選題流程管理:實現選題申請、審核、分配等流程的自動化管理。
數據統計與分析:提供選題情況統計、師生匹配情況分析等功能。 系統設置:支持系統參數配置、用戶權限管理等功能。
2.2 非功能需求
性能需求:系統響應時間應控制在合理范圍內,確保用戶操作的流暢性。
安全性需求:保證用戶數據的安全性,防止未授權訪問和數據泄露。
易用性需求:界面設計應簡潔明了,操作方便快捷,降低用戶學習成本。
可擴展性需求:系統應具有良好的擴展性,便于未來功能的升級和擴展。
系統設計
3.1 總體架構設計
系統采用三層架構設計,包括表示層、業務邏輯層和數據訪問層: 表示層:負責與用戶進行交互,展示系統界面。
業務邏輯層:負責處理系統的業務邏輯,實現各種功能。
數據訪問層:負責與數據庫進行交互,實現數據的存儲和讀取。
3.2 數據庫設計
系統使用SQLite數據庫,主要包含以下數據表:
用戶表(users):存儲用戶基本信息,包括用戶名、密碼、角色等。
選題表(topics):存儲選題信息,包括選題標題、描述、指導教師等。
選題記錄表(topic_records):記錄學生選題申請的歷史和狀態。 教師信息表(teachers):存儲教師的詳細信息。
學生信息表(students):存儲學生的詳細信息。
3.3 模塊設計
系統分為以下幾個主要模塊:
用戶管理模塊:負責用戶的注冊、登錄和權限管理。
選題管理模塊:負責選題的發布、查詢和維護。
選題流程模塊:負責選題申請、審核和分配的流程管理。
數據統計模塊:負責數據的統計和分析。
系統設置模塊:負責系統參數的配置和管理。
系統實現
4.1 開發環境
編程語言:Python 3.9
開發工具:PyCharm
數據庫:SQLite
界面庫:Tkinter
版本控制:Git
4.2 核心功能實現 以下是系統的核心代碼實現:
import tkinter as tk
from tkinter import ttk, messagebox
import sqlite3
import hashlib
import os
from datetime import datetimeclass ThesisManagementSystem:def __init__(self, root):self.root = rootself.root.title("畢業設計選題管理系統")self.root.geometry("1024x768")self.current_user = Noneself.current_role = None# 創建數據庫self.create_database()# 創建主界面self.create_main_frame()# 添加示例數據self.add_sample_data()def create_database(self):"""創建數據庫和表結構"""if not os.path.exists("thesis_management.db"):conn = sqlite3.connect("thesis_management.db")c = conn.cursor()# 創建用戶表c.execute('''CREATE TABLE users(id INTEGER PRIMARY KEY AUTOINCREMENT,username TEXT NOT NULL UNIQUE,password TEXT NOT NULL,role TEXT NOT NULL,name TEXT,student_id TEXT,department TEXT,email TEXT,phone TEXT)''')# 創建選題表c.execute('''CREATE TABLE topics(id INTEGER PRIMARY KEY AUTOINCREMENT,title TEXT NOT NULL,description TEXT,teacher_id INTEGER NOT NULL,teacher_name TEXT NOT NULL,department TEXT,status TEXT NOT NULL DEFAULT '未選',student_id INTEGER,student_name TEXT,create_time TEXT,FOREIGN KEY (teacher_id) REFERENCES users (id))''')# 創建選題記錄表c.execute('''CREATE TABLE topic_records(id INTEGER PRIMARY KEY AUTOINCREMENT,topic_id INTEGER NOT NULL,student_id INTEGER NOT NULL,student_name TEXT NOT NULL,status TEXT NOT NULL,apply_time TEXT,approve_time TEXT,teacher_feedback TEXT,FOREIGN KEY (topic_id) REFERENCES topics (id),FOREIGN KEY (student_id) REFERENCES users (id))''')conn.commit()conn.close()def add_sample_data(self):"""添加示例數據"""conn = sqlite3.connect("thesis_management.db")c = conn.cursor()# 檢查是否已有數據c.execute("SELECT COUNT(*) FROM users")count = c.fetchone()[0]if count == 0:# 添加管理員admin_password = hashlib.sha256("admin123".encode()).hexdigest()c.execute("INSERT INTO users (username, password, role, name) VALUES (?, ?, ?, ?)",("admin", admin_password, "管理員", "系統管理員"))# 添加教師teacher_password = hashlib.sha256("teacher123".encode()).hexdigest()c.execute("INSERT INTO users (username, password, role, name, department, email, phone) VALUES (?, ?, ?, ?, ?, ?, ?)",("teacher1", teacher_password, "教師", "張三", "計算機科學與技術", "zhangsan@example.com", "13800138001"))c.execute("INSERT INTO users (username, password, role, name, department, email, phone) VALUES (?, ?, ?, ?, ?, ?, ?)",("teacher2", teacher_password, "教師", "李四", "軟件工程", "lisi@example.com", "13800138002"))# 添加學生student_password = hashlib.sha256("student123".encode()).hexdigest()c.execute("INSERT INTO users (username, password, role, name, student_id, department, email, phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",("student1", student_password, "學生", "王五", "20210001", "計算機科學與技術", "wangwu@example.com", "13800138003"))c.execute("INSERT INTO users (username, password, role, name, student_id, department, email, phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",("student2", student_password, "學生", "趙六", "20210002", "軟件工程", "zhaoliu@example.com", "13800138004"))# 添加選題now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")c.execute("SELECT id FROM users WHERE username = 'teacher1'")teacher1_id = c.fetchone()[0]c.execute("SELECT id FROM users WHERE username = 'teacher2'")teacher2_id = c.fetchone()[0]c.execute("INSERT INTO topics (title, description, teacher_id, teacher_name, department, create_time) VALUES (?, ?, ?, ?, ?, ?)",("基于深度學習的圖像識別系統研究", "研究基于深度學習的圖像識別技術,實現高效準確的圖像分類。", teacher1_id, "張三", "計算機科學與技術", now))c.execute("INSERT INTO topics (title, description, teacher_id, teacher_name, department, create_time) VALUES (?, ?, ?, ?, ?, ?)",("大數據分析在電商推薦系統中的應用", "研究大數據分析技術在電商推薦系統中的應用,提高推薦準確率。", teacher2_id, "李四", "軟件工程", now))conn.commit()conn.close()def create_main_frame(self):"""創建主界面"""# 清除現有界面for widget in self.root.winfo_children():widget.destroy()# 創建登錄框架login_frame = ttk.Frame(self.root, padding="30 30 30 30")login_frame.pack(fill=tk.BOTH, expand=True)# 標題ttk.Label(login_frame, text="畢業設計選題管理系統", font=("Arial", 20, "bold")).grid(column=0, row=0, columnspan=2, pady=20)# 用戶名ttk.Label(login_frame, text="用戶名:").grid(column=0, row=1, sticky=tk.W, pady=5)username_entry = ttk.Entry(login_frame, width=30)username_entry.grid(column=1, row=1, sticky=tk.W, pady=5)# 密碼ttk.Label(login_frame, text="密碼:").grid(column=0, row=2, sticky=tk.W, pady=5)password_entry = ttk.Entry(login_frame, width=30, show="*")password_entry.grid(column=1, row=2, sticky=tk.W, pady=5)# 登錄按鈕login_button = ttk.Button(login_frame, text="登錄", command=lambda: self.login(username_entry.get(), password_entry.get()))login_button.grid(column=1, row=3, sticky=tk.W, pady=20)# 調整布局for child in login_frame.winfo_children():child.grid_configure(padx=5, pady=5)# 設置焦點username_entry.focus()def login(self, username, password):"""用戶登錄驗證"""if not username or not password:messagebox.showerror("錯誤", "用戶名和密碼不能為空")returnconn = sqlite3.connect("thesis_management.db")c = conn.cursor()# 驗證用戶hashed_password = hashlib.sha256(password.encode()).hexdigest()c.execute("SELECT id, role, name FROM users WHERE username = ? AND password = ?", (username, hashed_password))user = c.fetchone()conn.close()if user:self.current_user = user[0]self.current_role = user[1]self.current_name = user[2]messagebox.showinfo("成功", f"歡迎 {self.current_name} ({self.current_role}) 登錄系統!")self.show_main_menu()else:messagebox.showerror("錯誤", "用戶名或密碼錯誤")def show_main_menu(self):"""顯示主菜單"""# 清除現有界面for widget in self.root.winfo_children():widget.destroy()# 創建主菜單框架menu_frame = ttk.Frame(self.root, padding="10 10 10 10")menu_frame.pack(fill=tk.BOTH, expand=True)# 頂部信息欄info_frame = ttk.Frame(menu_frame)info_frame.pack(fill=tk.X, pady=5)ttk.Label(info_frame, text=f"當前用戶: {self.current_name} ({self.current_role})").pack(side=tk.LEFT, padx=10)ttk.Button(info_frame, text="退出登錄", command=self.create_main_frame).pack(side=tk.RIGHT, padx=10)# 功能按鈕區域buttons_frame = ttk.Frame(menu_frame)buttons_frame.pack(fill=tk.BOTH, expand=True, pady=20)if self.current_role == "管理員":# 管理員功能ttk.Button(buttons_frame, text="用戶管理", command=self.manage_users).pack(fill=tk.X, pady=10, padx=20)ttk.Button(buttons_frame, text="選題管理", command=self.manage_topics).pack(fill=tk.X, pady=10, padx=20)ttk.Button(buttons_frame, text="選題統計", command=self.statistics_topics).pack(fill=tk.X, pady=10, padx=20)elif self.current_role == "教師":# 教師功能ttk.Button(buttons_frame, text="添加選題", command=self.add_topic).pack(fill=tk.X, pady=10, padx=20)ttk.Button(buttons_frame, text="管理選題", command=lambda: self.manage_my_topics(self.current_user)).pack(fill=tk.X, pady=10, padx=20)ttk.Button(buttons_frame, text="選題申請審批", command=self.approve_topics).pack(fill=tk.X, pady=10, padx=20)ttk.Button(buttons_frame, text="查看我的學生", command=self.view_my_students).pack(fill=tk.X, pady=10, padx=20)elif self.current_role == "學生":# 學生功能ttk.Button(buttons_frame, text="查看選題", command=self.view_topics).pack(fill=tk.X, pady=10, padx=20)ttk.Button(buttons_frame, text="申請選題", command=self.apply_topic).pack(fill=tk.X, pady=10, padx=20)ttk.Button(buttons_frame, text="我的選題", command=lambda: self.view_my_topic(self.current_user)).pack(fill=tk.X, pady=10, padx=20)ttk.Button(buttons_frame, text="選題歷史", command=lambda: self.view_topic_history(self.current_user)).pack(fill=tk.X, pady=10, padx=20)def manage_users(self):"""用戶管理界面"""# 清除現有界面for widget in self.root.winfo_children():widget.destroy()# 創建用戶管理框架user_frame = ttk.Frame(self.root, padding="10 10 10 10")user_frame.pack(fill=tk.BOTH, expand=True)# 頂部信息欄info_frame = ttk.Frame(user_frame)info_frame.pack(fill=tk.X, pady=5)ttk.Label(info_frame, text="用戶管理").pack(side=tk.LEFT, padx=10)ttk.Button(info_frame, text="返回", command=self.show_main_menu).pack(side=tk.RIGHT, padx=10)ttk.Button(info_frame, text="添加用戶", command=self.add_user).pack(side=tk.RIGHT, padx=10)# 搜索框search_frame = ttk.Frame(user_frame)search_frame.pack(fill=tk.X, pady=5)ttk.Label(search_frame, text="搜索:").pack(side=tk.LEFT, padx=10)search_entry = ttk.Entry(search_frame, width=30)search_entry.pack(side=tk.LEFT, padx=10)ttk.Label(search_frame, text="角色:").pack(side=tk.LEFT, padx=10)role_var = tk.StringVar()role_combobox = ttk.Combobox(search_frame, textvariable=role_var, values=["全部", "管理員", "教師", "學生"], width=10)role_combobox.pack(side=tk.LEFT, padx=10)role_combobox.current(0)ttk.Button(search_frame, text="搜索", command=lambda: self.search_users(search_entry.get(), role_var.get())).pack(side=tk.LEFT, padx=10)# 用戶表格columns = ("id", "username", "role", "name", "student_id", "department", "email", "phone")user_tree = ttk.Treeview(user_frame, columns=columns, show="headings")# 設置列標題user_tree.heading("id", text="ID")user_tree.heading("username", text="用戶名")user_tree.heading("role", text="角色")user_tree.heading("name", text="姓名")user_tree.heading("student_id", text="學號/工號")user_tree.heading("department", text="院系")user_tree.heading("email", text="郵箱")user_tree.heading("phone", text="電話")# 設置列寬user_tree.column("id", width=50)user_tree.column("username", width=100)user_tree.column("role", width=80)user_tree.column("name", width=100)user_tree.column("student_id", width=120)user_tree.column("department", width=150)user_tree.column("email", width=150)user_tree.column("phone", width=120)user_tree.pack(fill=tk.BOTH, expand=True, pady=10)# 添加滾動條scrollbar = ttk.Scrollbar(user_tree, orient="vertical", command=user_tree.yview)user_tree.configure(yscroll=scrollbar.set)scrollbar.pack(side=tk.RIGHT, fill=tk.Y)# 綁定雙擊事件user_tree.bind("<Double-1>", lambda event: self.edit_user(user_tree))# 加載用戶數據self.load_users(user_tree)def load_users(self, tree):"""加載用戶數據到表格"""# 清空表格for item in tree.get_children():tree.delete(item)conn = sqlite3.connect("thesis_management.db")c = conn.cursor()# 查詢用戶c.execute("SELECT id, username, role, name, student_id, department, email, phone FROM users ORDER BY id")users = c.fetchall()conn.close()# 添加到表格for user in users:tree.insert("", tk.END, values=user)def search_users(self, keyword, role):"""搜索用戶"""# 清空表格user_tree = self.root.winfo_children()[1].winfo_children()[2]for item in user_tree.get_children():user_tree.delete(item)conn = sqlite3.connect("thesis_management.db")c = conn.cursor()# 構建查詢條件query = "SELECT id, username, role, name, student_id, department, email, phone FROM users WHERE 1=1"params = []if keyword:query += " AND (username LIKE ? OR name LIKE ? OR student_id LIKE ?)"params.extend([f"%{keyword}%", f"%{keyword}%", f"%{keyword}%"])if role and role != "全部":query += " AND role = ?"params.append(role)query += " ORDER BY id"# 執行查詢c.execute(query, params)users = c.fetchall()conn.close()# 添加到表格for user in users:user_tree.insert("", tk.END, values=user)def add_user(self):"""添加用戶對話框"""add_window = tk.Toplevel(self.root)add_window.title("添加用戶")add_window.geometry("400x350")add_window.resizable(False, False)# 創建表單form_frame = ttk.Frame(add_window, padding="20 20 20 20")form_frame.pack(fill=tk.BOTH, expand=True)# 用戶名ttk.Label(form_frame, text="用戶名:").grid(column=0, row=0, sticky=tk.W, pady=5)username_entry = ttk.Entry(form_frame, width=30)username_entry.grid(column=1, row=0, sticky=tk.W, pady=5)# 密碼ttk.Label(form_frame, text="密碼:").grid(column=0, row=1, sticky=tk.W, pady=5)password_entry = ttk.Entry(form_frame, width=30, show="*")password_entry.grid(column=1, row=1, sticky=tk.W, pady=5)# 確認密碼ttk.Label(form_frame, text="確認密碼:").grid(column=0, row=2, sticky=tk.W, pady=5)confirm_entry = ttk.Entry(form_frame, width=30, show="*")confirm_entry.grid(column=1, row=2, sticky=tk.W, pady=5)# 角色ttk.Label(form_frame, text="角色:").grid(column=0, row=3, sticky=tk.W, pady=5)role_var = tk.StringVar()role_combobox = ttk.Combobox(form_frame, textvariable=role_var, values=["管理員", "教師", "學生"], width=27)role_combobox.grid(column=1, row=3, sticky=tk.W, pady=5)role_combobox.current(0)# 姓名ttk.Label(form_frame, text="姓名:").grid(column=0, row=4, sticky=tk.W, pady=5)name_entry = ttk.Entry(form_frame, width=30)name_entry.grid(column=1, row=4, sticky=tk.W, pady=5)# 學號/工號ttk.Label(form_frame, text="學號/工號:").grid(column=0, row=5, sticky=tk.W, pady=5)id_entry = ttk.Entry(form_frame, width=30)id_entry.grid(column=1, row=5, sticky=tk.W, pady=5)# 院系ttk.Label(form_frame, text="院系:").grid(column=0, row=6, sticky=tk.W, pady=5)department_entry = ttk.Entry(form_frame, width=30)department_entry.grid(column=1, row=6, sticky=tk.W, pady=5)# 郵箱ttk.Label(form_frame, text="郵箱:").grid(column=0, row=7, sticky=tk.W, pady=5)email_entry = ttk.Entry(form_frame, width=30)email_entry.grid(column=1, row=7, sticky=tk.W, pady=5)# 電話ttk.Label(form_frame, text="電話:").grid(column=0, row=8, sticky=tk.W, pady=5)phone_entry = ttk.Entry(form_frame, width=30)phone_entry.grid(column=1, row=8, sticky=tk.W, pady=5)# 按鈕button_frame = ttk.Frame(add_window)button_frame.pack(fill=tk.X, pady=10)ttk.Button(button_frame, text="保存", command=lambda: self.save_user(username_entry.get(), password_entry.get(), confirm_entry.get(), role_var.get(), name_entry.get(), id_entry.get(), department_entry.get(), email_entry.get(), phone_entry.get(), add_window)).pack(side=tk.RIGHT, padx=10)ttk.Button(button_frame, text="取消", command=add_window.destroy).pack(side=tk.RIGHT, padx=10)def save_user(self, username, password, confirm_password, role, name, student_id, department, email, phone, window):"""保存用戶信息"""if not username or not password:messagebox.showerror("錯誤", "用戶名和密碼不能為空")returnif password != confirm_password:messagebox.showerror("錯誤", "兩次輸入的密碼不一致")returnconn = sqlite3.connect("thesis_management.db")c = conn.cursor()try:# 檢查用戶名是否已存在c.execute("SELECT id FROM users WHERE username = ?", (username,))if c.fetchone():messagebox.showerror("錯誤", "用戶名已存在")conn.close()return# 加密密碼hashed_password = hashlib.sha256(password.encode()).hexdigest()# 插入用戶if role == "學生":c.execute("INSERT INTO users (username, password, role, name, student_id, department, email, phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",(username, hashed_password, role, name, student_id, department, email, phone))else:c.execute("INSERT INTO users (username, password, role, name, department, email, phone) VALUES (?, ?, ?, ?, ?, ?, ?)",(username, hashed_password, role, name, department, email, phone))conn.commit()messagebox.showinfo("成功", "用戶添加成功")window.destroy()# 刷新用戶列表user_tree = self.root.winfo_children()[1].winfo_children()[2]self.load_users(user_tree)except Exception as e:messagebox.showerror("錯誤", f"添加用戶失敗: {str(e)}")finally:conn.close()def edit_user(self, tree):"""編輯用戶信息"""selected_item = tree.selection()if not selected_item:messagebox.showinfo("提示", "請選擇要編輯的用戶")returnuser_id = tree.item(selected_item[0])['values'][0]conn = sqlite3.connect("thesis_management.db")c = conn.cursor()# 查詢用戶信息c.execute("SELECT username, role, name, student_id, department, email, phone FROM users WHERE id = ?", (user_id,))user = c.fetchone()conn.close()if not user:messagebox.showerror("錯誤", "用戶不存在")return# 創建編輯窗口edit_window = tk.Toplevel(self.root)edit_window.title("編輯用戶")edit_window.geometry("400x350")edit_window.resizable(False, False)# 創建表單form_frame = ttk.Frame(edit_window, padding="20 20 20 20")form_frame.pack(fill=tk.BOTH, expand=True)# 用戶名ttk.Label(form_frame, text="用戶名:").grid(column=0, row=0, sticky=tk.W, pady=5)username_var = tk.StringVar(value=user[0])username_entry = ttk.Entry(form_frame, textvariable=username_var, width=30)username_entry.grid(column=1, row=0, sticky=tk.W, pady=5)username_entry.config(state="readonly") # 用戶名不可修改# 密碼ttk.Label(form_frame, text="新密碼:").grid(column=0, row=1, sticky=tk.W, pady=5)password_entry = ttk.Entry(form_frame, width=30, show="*")password_entry.grid(column=1, row=1, sticky=tk.W, pady=5)# 確認密碼ttk.Label(form_frame, text="確認新密碼:").grid(column=0, row=2, sticky=tk.W, pady=5)confirm_entry = ttk.Entry(form_frame, width=30, show="*")confirm_entry.grid(column=1, row=2, sticky=tk.W, pady=5)# 角色ttk.Label(form_frame, text="角色:").grid(column=0, row=3, sticky=tk.W, pady=5)role_var = tk.StringVar(value=user[1])role_combobox = ttk.Combobox(form_frame, textvariable=role_var, values=["管理員", "教師", "學生"], width=27)role_combobox.grid(column=1, row=3, sticky=tk.W, pady=5)# 姓名ttk.Label(form_frame, text="姓名:").grid(column=0, row=4, sticky=tk.W, pady=5)name_var = tk.StringVar(value=user[2])name_entry = ttk.Entry(form_frame, textvariable=name_var, width=30)name_entry.grid(column=1, row=4, sticky=tk.W, pady=5)# 學號/工號ttk.Label(form_frame, text="學號/工號:").grid(column=0, row=5, sticky=tk.W, pady=5)id_var = tk.StringVar(value=user[3] if user[3] else "")id_entry = ttk.Entry(form_frame, textvariable=id_var, width=30)id_entry.grid(column=1, row=5, sticky=tk.W, pady=5)# 院系ttk.Label(form_frame, text="院系:").grid(column=0, row=6, sticky=tk.W, pady=5)department_var = tk.StringVar(value=user[4] if user[4] else "")department_entry = ttk.Entry(form_frame, textvariable=department_var, width=30)department_entry.grid(column=1, row=6, sticky=tk.W, pady=5)# 郵箱ttk.Label(form_frame, text="郵箱:").grid(column=0, row=7, sticky=tk.W, pady=5)email_var = tk.StringVar(value=user[5] if user[5] else "")email_entry = ttk.Entry(form_frame, textvariable=email_var, width=30)email_entry.grid(column=1, row=7, sticky=tk.W, pady=5)# 電話ttk.Label(form_frame, text="電話:").grid(column=0, row=8, sticky=tk.W, pady=5)phone_var = tk.StringVar(value=user[6] if user[6] else "")phone_entry = ttk.Entry(form_frame, textvariable=phone_var, width=30)phone_entry.grid(column=1, row=8, sticky=tk.W, pady=5)# 按鈕button_frame = ttk.Frame(edit_window)button_frame.pack(fill=tk.X, pady=10)ttk.Button(button_frame, text="保存", command=lambda: self.update_user(user_id, password_entry.get(), confirm_entry.get(), role_var.get(), name_var.get(), id_var.get(), department_var.get(), email_var.get(), phone_var.get(), edit_window, tree)).pack(side=tk.RIGHT, padx=10)ttk.Button(button_frame, text="取消", command=edit_window.destroy).pack(side=tk.RIGHT, padx=10)def update_user(self, user_id, password, confirm_password, role, name, student_id, department, email, phone, window, tree):"""更新用戶信息"""if password and password != confirm_password:messagebox.showerror("錯誤", "兩次輸入的密碼不一致")returnconn = sqlite3.connect("thesis_management.db")c = conn.cursor()try:# 更新用戶信息if password:# 加密新密碼hashed_password = hashlib.sha256(password.encode()).hexdigest()if role == "學生":c.execute("UPDATE users SET password = ?, role = ?, name = ?, student_id = ?, department = ?, email = ?, phone = ? WHERE id = ?",(hashed_password, role, name, student_id, department, email, phone, user_id))else:c.execute("UPDATE users SET password = ?, role = ?, name = ?, department = ?, email = ?, phone = ?, student_id = NULL WHERE id = ?",(hashed_password, role, name, department, email, phone, user_id))else:if role == "學生":c.execute("UPDATE users SET role = ?, name = ?, student_id = ?, department = ?, email = ?, phone = ? WHERE id = ?",(role, name, student_id, department, email, phone, user_id))else:c.execute("UPDATE users SET role = ?, name = ?, department = ?, email = ?, phone = ?, student_id = NULL WHERE id = ?",(role, name, department, email, phone, user_id))conn.commit()messagebox.showinfo("成功", "用戶信息更新成功")window.destroy()# 刷新用戶列表self.load_users(tree)except Exception as e:messagebox.showerror("錯誤", f"更新用戶失敗: {str(e)}")finally:conn.close()# 其他功能實現... (代碼太長,此處省略其他方法的實現)if __name__ == "__main__":root = tk.Tk()app = ThesisManagementSystem(root)root.mainloop()
4.3 界面設計
系統采用Tkinter庫實現圖形用戶界面,主要包括以下界面:
登錄界面:用戶登錄系統的入口。
主菜單界面:根據用戶角色顯示不同的功能菜單。
選題管理界面:教師發布和管理選題的界面。
選題瀏覽界面:學生查看和申請選題的界面。
選題審批界面:教師審批學生選題申請的界面。
用戶管理界面:管理員管理用戶信息的界面。
系統測試
5.1 測試環境
操作系統:Windows 10
Python版本:3.9
數據庫:SQLite 3
5.2 測試方法與用例
采用黑盒測試方法,設計了以下測試用例:
用戶登錄測試:驗證不同角色用戶能否成功登錄系統。
選題管理測試:驗證教師能否正常發布、修改和刪除選題。
選題申請測試:驗證學生能否正常查看和申請選題。
選題審批測試:驗證教師能否正常審批學生的選題申請。
數據統計測試:驗證系統能否正確統計選題情況和師生匹配情況。
5.3 測試結果
通過對系統的功能和性能進行測試,結果表明系統能夠滿足高校畢業設計選題管理的基本需求,各項功能運行正常,界面友好,操作簡便。
總結與展望
6.1 研究成果總結
本論文成功設計并實現了一個基于Python的畢業設計選題管理系統,該系統具有以下特點:
采用模塊化設計,提高了系統的可維護性和可擴展性。
使用SQLite數據庫,簡化了系統部署和維護。
實現了用戶權限管理,確保了數據的安全性。
提供了友好的用戶界面,降低了用戶的使用難度。
6.2 不足與展望
盡管系統已經實現了預期的功能,但仍存在一些不足之處,例如:
缺乏移動端支持,用戶體驗有待提升。
統計分析功能還不夠完善,需要進一步增強。
系統的安全性還需要進一步加強。
未來的工作將主要集中在以下幾個方面:
開發移動端應用,實現多平臺支持。
增強系統的統計分析功能,提供更多的數據可視化方式。
加強系統的安全防護,提高系統的安全性。