效果图:
代码目录:
代码:
main.py
import tkinter as tk
from tkinter import messagebox
from student_manager import StudentManager
from observer import StudentObserver
from factory import StudentFactory
from strategy import SortByName, SortByGrade
from proxy import StudentProxy
from command import AddStudentCommand, RemoveStudentCommand
from DatabaseConnection import DatabaseConnection
class StudentApp:
def __init__(self, root):
self.root = root
self.root.title("学生信息管理系统")
self.root.geometry("600x600")
screenwidth = self.root.winfo_screenwidth()
screenheight = self.root.winfo_screenheight()
alignstr = '%dx%d+%d+%d' % (600, 600, (screenwidth - 600) / 2, (screenheight - 600) / 2)
self.root.geometry(alignstr)
self.root.resizable(False, False) # 禁止调整窗口大小
# 初始化学生管理器和观察者
self.student_manager = StudentManager()
self.student_observer = StudentObserver()
self.student_manager.observers.append(self.student_observer)
# 学生列表框,显示学生
self.student_listbox_label = tk.Label(root, text="学生列表", font=("Arial", 14))
self.student_listbox_label.pack(pady=10)
# 表头区域(姓名和学号)
self.header_frame = tk.Frame(root)
self.header_frame.pack(padx=10, pady=5)
# Adjust the padx to align headers with the listbox content
self.name_header = tk.Label(self.header_frame, text="姓名", width=15, anchor="w", font=("Arial", 12, "bold"))
self.name_header.grid(row=0, column=0, padx=10, pady=5)
self.id_header = tk.Label(self.header_frame, text="学号", width=20, anchor="w", font=("Arial", 12, "bold"))
self.id_header.grid(row=0, column=1, padx=5, pady=5)
# 学生列表框,显示学生
self.student_listbox = tk.Listbox(root, width=40, height=10, selectmode=tk.SINGLE, font=("Arial", 12))
self.student_listbox.pack(padx=10, pady=10)
# 输入框区域
self.input_frame = tk.Frame(root)
self.input_frame.pack(pady=10)
# 学生姓名输入框
self.name_label = tk.Label(self.input_frame, text="姓名:", width=20, anchor="w", font=("Arial", 12))
self.name_label.grid(row=0, column=0, padx=10, pady=5)
self.name_entry = tk.Entry(self.input_frame, width=30, font=("Arial", 12))
self.name_entry.grid(row=0, column=1, padx=10, pady=5)
# 学生学号输入框
self.student_id_label = tk.Label(self.input_frame, text="学号:", width=20, anchor="w", font=("Arial", 12))
self.student_id_label.grid(row=1, column=0, padx=10, pady=5)
self.student_id_entry = tk.Entry(self.input_frame, width=30, font=("Arial", 12))
self.student_id_entry.grid(row=1, column=1, padx=10, pady=5)
# 查看学生姓名输入框
self.view_name_label = tk.Label(self.input_frame, text="查看信息(姓名):", width=20, anchor="w",
font=("Arial", 12))
self.view_name_label.grid(row=2, column=0, padx=10, pady=5)
self.view_name_entry = tk.Entry(self.input_frame, width=30, font=("Arial", 12))
self.view_name_entry.grid(row=2, column=1, padx=10, pady=5)
# 按钮区域
self.button_frame = tk.Frame(root)
self.button_frame.pack(pady=10)
# 添加学生按钮
self.add_button = tk.Button(self.button_frame, text="添加学生", width=20, bg="lightgreen",
font=("Arial", 12), command=self.add_student)
self.add_button.grid(row=0, column=0, padx=10, pady=5)
# 删除学生按钮
self.remove_button = tk.Button(self.button_frame, text="移除学生", width=20, bg="lightcoral",
font=("Arial", 12), command=self.remove_student)
self.remove_button.grid(row=0, column=1, padx=10, pady=5)
# 排序按钮
self.sort_button = tk.Button(self.button_frame, text="排序(按姓名)", width=20, bg="lightblue",
font=("Arial", 12), command=self.sort_by_name)
self.sort_button.grid(row=1, column=0, padx=10, pady=5)
self.sort_grade_button = tk.Button(self.button_frame, text="排序(按学号)", width=20, bg="lightblue",
font=("Arial", 12), command=self.sort_by_grade)
self.sort_grade_button.grid(row=1, column=1, padx=10, pady=5)
# 查看学生按钮
self.view_button = tk.Button(self.button_frame, text="查看", width=20, bg="lightyellow",
font=("Arial", 12), command=self.view_student)
self.view_button.grid(row=2, column=0, columnspan=2, pady=5)
def add_student(self):
name = self.name_entry.get()
student_id = self.student_id_entry.get()
if not name or not student_id:
messagebox.showwarning("错误!", "请同时输入学号和姓名")
return
student = StudentFactory.create_student(name, student_id)
add_command = AddStudentCommand(self.student_manager, student)
add_command.execute()
self.update_student_list()
def remove_student(self):
selected_student_index = self.student_listbox.curselection()
if not selected_student_index:
messagebox.showwarning("错误!", "请选择要移除的学生")
return
student = self.student_manager.get_all_students()[selected_student_index[0]]
remove_command = RemoveStudentCommand(self.student_manager, student)
remove_command.execute()
self.update_student_list()
def sort_by_name(self):
strategy = SortByName()
self.student_manager.students = strategy.sort(self.student_manager.students)
self.update_student_list()
def sort_by_grade(self):
strategy = SortByGrade()
self.student_manager.students = strategy.sort(self.student_manager.students)
self.update_student_list()
def update_student_list(self):
# 清空现有列表内容
self.student_listbox.delete(0, tk.END)
# 更新列表内容:每一行显示 "姓名 学号"(增加间隔)
for student in self.student_manager.get_all_students():
display_text = f"{student.name:<35} {student.student_id}" # 增加空格以增加间隔
self.student_listbox.insert(tk.END, display_text)
def view_student(self):
# 获取输入框中的学生姓名
student_name = self.view_name_entry.get().strip()
if not student_name:
messagebox.showwarning("错误!", "请输入学生姓名")
return
# 在学生列表中查找对应学生
student_found = None
for student in self.student_manager.get_all_students():
if student.name == student_name:
student_found = student
break
if not student_found:
messagebox.showwarning("未查找到学生", f"No student found with name: {student_name}")
return
# 如果找到学生,通过代理类查看其信息
proxy = StudentProxy(student_found)
proxy.grant_permission()
student_info = proxy.get_student_info()
messagebox.showinfo("学生信息", student_info)
if __name__ == "__main__":
root = tk.Tk()
app = StudentApp(root)
root.mainloop()
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2) # 输出: True,表示db1和db2是同一个实例
print(db1._connection) # 输出: "Database Connection Established"
studentmanage.py:
# student_manager.py
import DatabaseConnection
class StudentManager:
def __init__(self):
self.students = []
self.observers = []
def add_student(self, student):
self.students.append(student)
self.notify(f"Student {student.name} added.")
def remove_student(self, student):
self.students.remove(student)
self.notify(f"Student {student.name} removed.")
def notify(self, message):
for observer in self.observers:
observer.update(message)
def get_all_students(self):
return self.students
def DataConnect(self):
db1 = DatabaseConnection()
connection = db1.connect(host='localhost', user='root', password='', database='studentmanager')
return connection
# 查询
def SelectFunction(self,sql):
connection =StudentManager.DataConnect()
cur = connection.cursor() # 建立游标
try:
cur.execute(sql)
result=cur.fetchall()
except Exception as e:
connection.rollback() #回滚
finally:
cur.close()
connection.close()
return result
# 封装更改数据库操作
def change_db(sql):
conn = StudentManager.DataConnect() # 获取连接
cur = conn.cursor() # 建立游标
try:
cur.execute(sql) # 执行sql
conn.commit() # 提交更改
except Exception as e:
conn.rollback() # 回滚
finally:
cur.close() # 关闭游标
conn.close() # 关闭连接4
def add_user(name, id):
sql = "insert into user (name, id) values ('{}','{}')".format(name, id)
StudentManager.change_db(sql)
def del_user(name):
sql = "delete from user where name='{}'".format(name)
StudentManager.change_db(sql)
command.py:
class Command:
def execute(self):
pass
class AddStudentCommand(Command):
def __init__(self, student_manager, student):
self._student_manager = student_manager
self._student = student
def execute(self):
self._student_manager.add_student(self._student)
class RemoveStudentCommand(Command):
def __init__(self, student_manager, student):
self._student_manager = student_manager
self._student = student
def execute(self):
self._student_manager.remove_student(self._student)
databaseconnection.py:
import pymysql
class DatabaseConnection:
_instance = None
_connection=None
def __new__(cls,*args,**kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def connect(self,host,user,password,database,port=3306,charset='utf8mb4'):
if self._connection is None or not self._connection.open:
try:
self._connection=pymysql.connect(
host=host,
user=user,
password=password,
database=database,
port=port,
charset=charset,
)
if self._connection.open:
print("成功连接数据库")
except pymysql.MySQLError as e:
print(f"无法连接数据库: {e}")
self._connection = None # 连接失败时设置为None
return self._connection
def get_connection(self):
# 如果连接已经关闭或从未建立,这里可以添加重新连接的逻辑,假设连接在创建后一直保持打开状态
return self._connection
def close_connection(self):
if self._connection and self._connection.is_connected():
self._connection.close()
print("MySQL连接已关闭")
self._connection = None # 设置为None以便下次可以重新连接
factory.py:
class Student:
def __init__(self, name, student_id):
self.name = name
self.student_id = student_id
def __str__(self):
return f"{self.name} ({self.student_id})"
class StudentFactory:
@staticmethod
def create_student(name, student_id):
return Student(name, student_id)
observe.py
# observer.py
class Observer:
def update(self, message):
pass
class StudentObserver(Observer):
def update(self, message):
print(f"Observer received: {message}")
proxy.py:
class StudentProxy:
def __init__(self, student=None):
self._student = student
self._has_permission = False #权限标志
self._info_cache = None # 缓存学生信息
self._access_log = [] # 访问日志
def grant_permission(self):
self._has_permission = False
self._access_log.append("Permission granted.")
def revoke_permission(self):
self._has_permission = False
self._access_log.append("Permission revoked.")
def get_student_info(self):
self._access_log.append("Attempted to get student info.")
if self._has_permission and self._student:
return str(self._student)
return "无法访问"
strategy.py:
class SortingStrategy:
def sort(self, students):
pass
class SortByName(SortingStrategy):
def sort(self, students):
return sorted(students, key=lambda student: student.name)
class SortByGrade(SortingStrategy):
def sort(self, students):
return sorted(students, key=lambda student: student.student_id) # Assuming student_id is a grade.
项目配置:
补充设计模式的相关内容:
1、工厂方法模式:展示如何定义一个创建对象的接口,让子类决定实例化哪一个类,以增强灵活性。
2、单例模式:实现确保一个类只有一个实例,并提供一个全局访问点的经典模式。
4、代理模式:代理模式的核心在于为某个对象提供一个代理对象,以控制对目标对象的访问
它为其他对象提供了一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用,客户端通过代理对象间接地访问目标对象。
当你需要一个访问控制层来检查客户端对目标对象的访问权限时。
当你希望隐藏目标对象的实现细节或复杂性时。
当你需要在访问目标对象之前执行一些额外的操作(如日志记录、安全检查等)时。
当你需要延迟加载目标对象,直到真正需要它时才创建时。
在你的StudentProxy类中,代理模式主要用于控制对student对象的访问权限。通过修改grant_permission方法,你可以正确地授予或拒绝访问权限。
3、命令模式:操作的执行者(如StudentManager)与请求者完全分离。通过命令对象,可以方便地实现撤销操作、操作日志记录等功能。
5、策略模式:允许在运行时改变对象的行为,展示了算法与上下文之间的解耦。动态选择不同的排序算法对学生列表进行排序
6、观察者模式:模拟一种一对多的关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。
门面模式:提供了一种方式来简化复杂系统的接口,使外部调用更加便捷。
1、创建型:创建对象,将对象的创建与使用分离,主要有工厂方法、单例模式
抽象化创建过程:创建型模式将创建对象的过程进行了抽象和封装,客户程序只需使用对象,而不必关心对象的创建逻辑。
单一实例控制:如单例模式,确保某个类只有一个实例,并提供全局访问点。
2、结构型:解决对象之间组合关系、接口定义和实现等结构性问题,通过组合对象或类以形成更强大的结构。
包括外观模式、适配器模式、代理模式、装饰模式、桥接模式、组合模式、享元模式
组合关系:关注对象或类之间的组合和关联关系,通过组合或聚合来构建更大的结构。
接口转换:如适配器模式,将一个类的接口转换成客户希望的另一个接口,使原本接口不兼容的类可以一起工作。
封装性:通过封装内部实现细节,提供简化的接口,降低系统的复杂性。
3、行为型:描述程序在运行时复杂的流程控制,即描述多个类或对象之间如何相互协作以完成单个对象都无法单独完成的任务
包括策略模式、模板方法模式、观察者模式、命令模式、迭代器模式、中介者模式、备忘录模式、状态模式、责任链模式、访问者模式
算法与职责分配:算法和对象间职责的分配,描述对象和类的行为以及它们之间的通信模式。
灵活性:通过封装算法或行为,使得系统在不同条件下可以灵活地选择不同的算法或行为。
对象间协作:强调对象之间的协作,通过组合或聚合来实现复杂的控制流和交互。