使用PyQt5库构建的图形用户界面(GUI)应用程序,它包含了学生管理系统和管理员管理系统。这个应用程序允许用户进行学生信息的注册、登录、查看、修改和删除,以及书籍库存的管理等功能。
应用概述
- 名称:学生管理系统
- 开发环境:Python,使用PyQt5库
- 功能:
- 学生注册
- 学生登录
- 成绩查看
- 书籍借阅和归还
- 管理员登录
- 学生信息管理(包括修改和删除)
- 成绩添加和更新
- 图书库存管理(添加、查看和删除)
主要类和功能
DeleteStudentDialog
:用于删除学生信息的对话框。AddStudentDialog
:用于添加学生信息的对话框,包含学号、姓名、年龄和性别的输入。StudentLoginDialog
:学生登录对话框,允许学生查看成绩和借阅书籍。AdminManagementSystem
:管理员管理系统对话框,提供学生信息管理、成绩管理、书籍库存管理等功能。StudentManagementSystem
:主窗口类,提供学生注册、登录和管理员登录的入口。
数据库操作
- 使用SQLite数据库存储学生、管理员和书籍信息。
- 数据库连接在
StudentManagementSystem
类中初始化,并在关闭事件中关闭。 - 使用
cursor
对象执行SQL语句进行数据库操作。
界面设计
- 应用使用了多个对话框(
QDialog
)来收集用户输入或显示信息。 - 使用了
QLineEdit
、QLabel
、QPushButton
、QGridLayout
等组件来设计界面。 - 通过
QHBoxLayout
和QVBoxLayout
来组织界面布局。
事件处理
- 通过
.clicked.connect()
方法将按钮点击事件连接到相应的处理函数。 - 例如,登录按钮点击会触发验证登录信息的函数。
样式定制
- 使用
setStyleSheet()
方法为不同的GUI组件设置样式。
异常处理
- 应用尝试捕获和处理
sqlite3.Error
和其他可能发生的异常。
运行条件
- 需要有Python环境和PyQt5库安装。
代码入口
- 程序的入口点是
if __name__ == '__main__':
部分,创建了QApplication
实例和主窗口StudentManagementSystem
,并进入事件循环。
结论
这段代码提供了一个完整的学生管理系统的实现,包括前台的学生交互界面和后台的数据库管理。它是一个典型的PyQt5应用程序,展示了如何使用事件驱动编程来创建交互式界面。
结果展示
图 1主界面
图 2学生注册界面
图 3学生登陆界面
图 4学生登陆成功可操作界面
图 5成绩查询
图 6借阅界面
图 7查看已借书籍和还书界面
图 8管理员登陆界面
图 9管理员登陆成功界面
代码使用注意事项
管理员默认为‘123’,‘123456’
代码包含的图片路径换成自己的图片
学生要先注册才可以使用
代码
import sys
from PyQt5.QtGui import QPixmap, QPalette, QBrush
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenuBar, QAction, QWidget, QVBoxLayout, QPushButton, \
QLineEdit, QLabel, QStatusBar, QToolBar, QListWidget, QDialog, QMessageBox, QComboBox, QHBoxLayout, QListWidgetItem, \
QSpinBox, QGridLayout, QSpacerItem, QSizePolicy
from PyQt5.QtCore import Qt
import sqlite3
import datetime
import logging
# 配置日志记录
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class DeleteStudentDialog(QDialog):
"""
定义一个删除学生对话框的类,继承自QDialog。
"""
def __init__(self, parent=None):
"""
初始化方法,设置对话框的基本属性和布局。
"""
super().__init__(parent)
self.setWindowTitle('选择学生删除') # 设置对话框标题
self.layout = QVBoxLayout(self) # 创建垂直布局
# 创建并添加列表小部件用于显示学生信息
self.list_widget = QListWidget()
self.layout.addWidget(self.list_widget)
# 创建水平布局用于放置按钮
button_layout = QHBoxLayout()
self.confirm_button = QPushButton('确认删除') # 创建确认按钮
self.cancel_button = QPushButton('取消') # 创建取消按钮
button_layout.addWidget(self.confirm_button) # 将确认按钮添加到水平布局
button_layout.addWidget(self.cancel_button) # 将取消按钮添加到水平布局
self.layout.addLayout(button_layout) # 将水平布局添加到垂直布局
# 连接按钮的信号到相应的方法
self.confirm_button.clicked.connect(self.confirm_delete) # 确认按钮点击时调用confirm_delete方法
self.cancel_button.clicked.connect(self.close) # 取消按钮点击时关闭对话框
def set_students(self, students):
"""
设置学生列表小部件中的学生信息。
"""
for student in students:
# 格式化学生信息并添加到列表小部件中
self.list_widget.addItem(f"ID: {student[0]}, 姓名: {student[1]}, 年龄: {student[2]}, 性别: {student[3]}")
def get_selected_student_id(self):
"""
获取当前选中学生的ID。
"""
selected_item = self.list_widget.currentItem() # 获取当前选中的列表项
if selected_item:
# 解析文本获取学生ID并返回
student_id = selected_item.text().split(':')[1].strip().split(',')[0]
return int(student_id)
else:
return None # 如果没有选中项,则返回None
def confirm_delete(self):
"""
处理确认删除操作。
"""
student_id = self.get_selected_student_id() # 获取选中学生的ID
if student_id is not None:
# 如果选中了学生,则关闭对话框并返回成功状态
print('here')
self.accept()
else:
# 如果没有选中学生,则显示警告消息框
QMessageBox.warning(self, '警告', '未选择学生!')
# ok
class AddStudentDialog(QDialog):
def __init__(self, parent=None, db_connection=None):
super().__init__(parent)
self.db_connection = db_connection # 保存数据库连接
self.initUI()
def initUI(self):
self.setWindowTitle('添加学生')
self.setGeometry(300, 300, 500, 400)
layout = QVBoxLayout()
# 设置全局样式表(可选)
self.setStyleSheet("""
QLabel {
font-weight: bold;
color: #333;
}
QLineEdit {
border: 1px solid #ccc;
border-radius: 10px;
padding: 5px;
font-size: 12pt;
background-color: #fff;
}
QPushButton {
padding: 5px 10px;
border: none;
border-radius: 3px;
background-color: #4CAF50;
color: white;
font-weight: bold;
}
QPushButton:hover {
background-color: #45a049;
}
""")
self.ID_label = QLabel('学号:')
self.ID_line_edit = QLineEdit()
self.name_label = QLabel('姓名:')
self.name_line_edit = QLineEdit()
self.age_label = QLabel('年龄:')
self.age_line_edit = QLineEdit()
self.gender_label = QLabel('性别:')
self.gender_combo_box = QComboBox()
self.gender_combo_box.addItem('男')
self.gender_combo_box.addItem('女')
self.add_button = QPushButton('添加', self)
self.add_button.clicked.connect(self.add_student)
layout.addWidget(self.ID_label)
layout.addWidget(self.ID_line_edit)
self.ID_line_edit.setFixedWidth(120)
layout.addWidget(self.name_label)
layout.addWidget(self.name_line_edit)
self.name_line_edit.setFixedWidth(120)
layout.addWidget(self.age_label)
layout.addWidget(self.age_line_edit)
self.age_line_edit.setFixedWidth(120)
layout.addWidget(self.gender_label)
layout.addWidget(self.gender_combo_box)
self.gender_combo_box.setFixedWidth(120)
layout.addWidget(self.add_button)
# 加载背景图片
palette = QPalette()
palette.setBrush(QPalette.Background, QBrush(QPixmap("studentadd_back.png")))
self.setPalette(palette)
self.setLayout(layout)
def add_student(self):
ID = self.ID_line_edit.text()
name = self.name_line_edit.text()
age = self.age_line_edit.text()
gender = self.gender_combo_box.currentText()
try:
cursor = self.db_connection.cursor()
# 插入学生信息
cursor.execute("INSERT INTO Students (id,name, age, gender) VALUES (?, ?, ?,?)", (ID, name, age, gender))
# 提交事务
self.db_connection.commit()
# 提示用户信息已保存
QMessageBox.information(self, "提示", "学生信息已保存")
except sqlite3.Error as e:
# 打印数据库错误
print(f"数据库错误: {e}")
QMessageBox.critical(self, "错误", f"数据库操作时出错: {e}")
except Exception as e:
# 打印其他异常
print(f"其他错误: {e}")
QMessageBox.critical(self, "错误", f"发生未知错误: {e}")
# 关闭模态对话框
self.accept()
class StudentLoginDialog(QDialog):
def __init__(self, parent=None, db_connection=None):
super().__init__(parent)
self.db_connection = db_connection
self.initUI()
def initUI(self):
self.setWindowTitle('学生登录')
self.setGeometry(300, 300, 400, 300)
# 创建网格布局
grid_layout = QGridLayout()
grid_layout.setSpacing(10) # 设置网格间距
grid_layout.setColumnStretch(1, 2) # 设置输入框列的伸缩因子
# 添加控件到网格布局
self.name_label = QLabel('姓名:')
self.name_line_edit = QLineEdit()
grid_layout.addWidget(self.name_label, 0, 0)
grid_layout.addWidget(self.name_line_edit, 0, 1)
self.password_label = QLabel('学号:')
self.password_line_edit = QLineEdit()
self.password_line_edit.setEchoMode(QLineEdit.Password)
grid_layout.addWidget(self.password_label, 1, 0)
grid_layout.addWidget(self.password_line_edit, 1, 1)
self.login_button = QPushButton('登录')
self.login_button.clicked.connect(self.login_student)
grid_layout.addWidget(self.login_button, 2, 1, Qt.AlignRight) # 右对齐登录按钮
# 设置样式
self.setStyleSheet("""
QLabel {
font-weight: bold;
color: #333;
}
QLineEdit {
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
font-size: 12pt;
background-color: #fff;
}
QPushButton {
padding: 5px 10px;
border: none;
border-radius: 3px;
background-color: #4CAF50;
color: white;
font-weight: bold;
}
QPushButton:hover {
background-color: #45a049;
}
""")
# 加载背景图片
palette = QPalette()
background_image = QPixmap("student_login.png").scaled(self.size(), Qt.KeepAspectRatio) # 调整图片大小
palette.setBrush(QPalette.Background, QBrush(background_image))
self.setPalette(palette)
self.setLayout(grid_layout)
def login_student(self):
name = self.name_line_edit.text()
password = self.password_line_edit.text()
try:
# 在数据库中检查是否存在该学生
cursor = self.db_connection.cursor()
cursor.execute("SELECT * FROM Students WHERE name=? AND id=?", (name, password))
student = cursor.fetchone()
if student:
# 创建一个对话框来显示学生的相关操作
dialog = QDialog(self)
dialog.setWindowTitle('学生操作')
# 创建一个布局
dialog_layout = QVBoxLayout()
dialog_layout.setSpacing(10) # 设置元素之间的间距
dialog_layout.setContentsMargins(10, 10, 10, 10)
# 添加一个按钮来查看成绩
self.view_score_button = QPushButton('查看成绩')
dialog_layout.addWidget(self.view_score_button)
self.view_score_button.clicked.connect(lambda: self.view_scores(student, name))
# 添加一个按钮来借书view_borrowed_books
self.borrow_book_button = QPushButton('借书')
dialog_layout.addWidget(self.borrow_book_button)
self.borrow_book_button.clicked.connect(lambda: self.view_inventory(password))
self.return_book_button = QPushButton('已借书籍和还书')
dialog_layout.addWidget(self.return_book_button)
self.return_book_button.clicked.connect(lambda: self.view_borrowed_books(password))
# 设置对话框的布局
dialog.setLayout(dialog_layout)
dialog.resize(300, 150)
# 显示对话框
dialog.exec_()
else:
QMessageBox.warning(self, "登录失败", "用户名或密码错误!")
except Exception as e:
print(f"An error occurred during student login: {e}")
QMessageBox.critical(self, '错误', f'学生登录时出错: {e}')
def view_scores(self, student, name):
try:
cursor = self.db_connection.cursor()
cursor.execute("SELECT subject, score FROM Scores WHERE student_id=?", (student[0],))
scores = cursor.fetchall()
if scores:
subject_scores = ", ".join(f"{subject}: {score}" for subject, score in scores)
QMessageBox.information(self, "成绩查询", f"欢迎回来,{name}!\n您的成绩是:\n{subject_scores}")
else:
QMessageBox.information(self, "成绩查询", f"欢迎回来,{name}!\n您还没有成绩记录。")
except Exception as e:
QMessageBox.critical(self, "错误", f"查询成绩时出现错误:{e}")
def view_inventory(self, id):
try:
# 创建一个对话框来显示书库内容
dialog = QDialog(self)
dialog.setWindowTitle('书库内容')
# 创建一个布局
dialog_layout = QVBoxLayout()
# 从数据库中检索书籍信息
cursor = self.db_connection.cursor()
cursor.execute("SELECT id, title, author, index_number, publisher, quantity FROM Books")
books = cursor.fetchall()
# 创建一个列表部件来显示书籍信息
list_widget = QListWidget()
for book in books:
item = QListWidgetItem(f"书名: {book[1]}, 作者: {book[2]}, 索引号: {book[3]}, 出版社: {book[4]}, 库存: {book[5]}")
item.setFlags(item.flags() | Qt.ItemIsUserCheckable) # 使用位运算来添加Qt.ItemIsUserCheckable
# 标志到项的当前标志中,这使得用户可以检查和取消检查该项
item.setCheckState(Qt.Unchecked) # 设置项的初始检查状态为未检查
list_widget.addItem(item)
# 将列表部件添加到布局中
dialog_layout.addWidget(list_widget)
# 创建一个按钮用于确认借阅选中的书籍
confirm_button = QPushButton('确认借阅')
dialog_layout.addWidget(confirm_button)
def confirm_borrow():
try:
# 获取当前选中的书籍索引
selected_item = list_widget.currentItem()
if selected_item:
selected_index = list_widget.row(selected_item)
selected_book = books[selected_index]
# 在这里执行借书操作,例如更新借阅状态等
# 这里可以根据具体情况添加借书逻辑
# 假设库存数量存储在元组的第五个位置(索引为4)
book_id = selected_book[0]
new_quantity = selected_book[5] - 1 # 减少库存数量
if new_quantity >= 0:
# 更新数据库中的库存数量
cursor.execute("UPDATE Books SET quantity=? WHERE id=?", (new_quantity, book_id))
self.db_connection.commit() # 提交事务
# 获取当前学生的学号
student_id = id
# 记录借书时间
# 记录借书时间
try:
borrow_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"Borrow date: {borrow_time}")
# 确保 student_id 和 book_id 不是 None
if student_id is None or book_id is None or borrow_time is None:
raise ValueError("Both student_id and book_id must be provided.")
# 向 BorrowedBooks 表中插入借书信息
cursor.execute(
"INSERT INTO BorrowedBooks (student_id, book_id, borrow_time) VALUES (?, ?, ?)",
(student_id, book_id, borrow_time)
)
self.db_connection.commit() # 提交事务
except sqlite3.IntegrityError as e:
print(f"数据库完整性错误: {e}")
# 在这里处理 NOT NULL 约束失败等问题
except Exception as e:
print(f"发生未知错误: {e}")
# 在这里处理其他异常
QMessageBox.information(dialog, '成功', f"成功借阅书籍:{selected_book[1]}。请在规定时间内归还。")
dialog.close()
else:
QMessageBox.warning(dialog, '库存不足', '抱歉,该书籍库存不足!')
else:
QMessageBox.warning(dialog, '提示', '请先选择要借阅的书籍!')
except Exception as e:
print(f"借阅书籍时出错: {e}")
QMessageBox.critical(dialog, '错误', f'借阅书籍时出错: {e}')
# 将确认按钮的点击事件与 confirm_borrow 函数关联
confirm_button.clicked.connect(confirm_borrow)
# 将布局设置到对话框中
dialog.setLayout(dialog_layout)
# 显示对话框
dialog.exec_()
except Exception as e:
print(f"查看书库时出错: {e}")
QMessageBox.critical(self, '错误', f'查看书库时出错: {e}')
def view_borrowed_books(self, student_id):
try:
# 创建一个对话框来显示已借书籍内容
dialog = QDialog(self)
dialog.setWindowTitle('已借书籍')
dialog.setGeometry(300, 300, 600, 400)
# 创建一个布局
dialog_layout = QVBoxLayout()
# 从数据库中检索该学生已借书籍信息
cursor = self.db_connection.cursor()
cursor.execute(
"SELECT BorrowedBooks.id, Books.id, Books.title, Books.author, BorrowedBooks.borrow_time FROM "
"BorrowedBooks "
"INNER JOIN Books ON BorrowedBooks.book_id = Books.id WHERE BorrowedBooks.student_id = ?",
(student_id,))
borrowed_books = cursor.fetchall()
# 创建一个列表部件来显示已借书籍信息
list_widget = QListWidget()
for book in borrowed_books:
item = QListWidgetItem(f"书名: {book[2]}, 作者: {book[3]}, 借阅日期: {book[4]}")
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
item.setCheckState(Qt.Unchecked)
list_widget.addItem(item)
# 将列表部件添加到布局中
dialog_layout.addWidget(list_widget)
# 创建一个按钮用于确认还书
return_button = QPushButton('还书')
dialog_layout.addWidget(return_button)
def return_book():
try:
# 获取当前选中的书籍索引
selected_item = list_widget.currentItem()
if selected_item:
selected_index = list_widget.row(selected_item)
selected_borrowed_book_id = borrowed_books[selected_index][0]
selected_book_id = borrowed_books[selected_index][1]
# 在这里执行还书操作,例如更新借阅状态等
# 这里可以根据具体情况添加还书逻辑
# 从借书记录中删除该条目
cursor.execute("DELETE FROM BorrowedBooks WHERE id=?", (selected_borrowed_book_id,))
# 将相应书籍的库存数量加1
cursor.execute("UPDATE Books SET quantity = quantity + 1 WHERE id=?", (selected_book_id,))
self.db_connection.commit() # 提交事务
QMessageBox.information(dialog, '成功', '成功还书!')
dialog.close()
else:
QMessageBox.warning(dialog, '提示', '请先选择要还的书籍!')
except Exception as e:
print(f"还书时出错: {e}")
QMessageBox.critical(dialog, '错误', f'还书时出错: {e}')
# 将还书按钮的点击事件与 return_book 函数关联
return_button.clicked.connect(return_book)
# 将布局设置到对话框中
dialog.setLayout(dialog_layout)
# 显示对话框
dialog.exec_()
except Exception as e:
print(f"查看已借书籍时出错: {e}")
QMessageBox.critical(self, '错误', f'查看已借书籍时出错: {e}')
class AdminManagementSystem(QDialog):
def __init__(self, parent=None, db_connection=None):
super().__init__(parent)
self.db_connection = db_connection
self.initDatabase()
self.admin_login()
def initUI(self):
# 设置窗口的标题为'管理员管理系统'
self.setWindowTitle('管理员管理系统')
# 设置窗口的位置和大小为:x=300, y=300, 宽度=600, 高度=400
self.setGeometry(300, 300, 400, 300)
layout = QHBoxLayout(self)
left_layout = QVBoxLayout()
right_layout = QVBoxLayout()
# 设置样式
self.setStyleSheet("""
QLabel {
font-weight: bold;
color: #333;
}
QLineEdit {
border: 1px solid #ccc;
border-radius: 10px;
padding: 5px;
font-size: 12pt;
background-color: #fff;
}
QPushButton {
padding: 5px 10px;
border: none;
border-radius: 8px;
background-color: #4CAF50;
color: white;
font-weight: bold;
}
QPushButton:hover {
background-color: #45a049;
}
""")
# 添加控件到布局中
self.modify_student_button = QPushButton('修改学生信息') # 创建一个按钮,用于修改学生信息
self.add_score_button = QPushButton('添加成绩') # 创建一个按钮,用于添加成绩
self.modify_score_button = QPushButton('修改学生成绩') # 创建一个按钮,用于添加成绩
self.add_Books = QPushButton('添加书籍')
self.view_button = QPushButton('查看书库')
self.view_database_button = QPushButton('查看学生数据库')
self.delete_student_button = QPushButton('删除学生信息')
left_layout.addWidget(self.modify_student_button)
self.modify_student_button.setFixedHeight(30)
left_layout.addWidget(self.add_score_button)
self.add_score_button.setFixedHeight(30)
left_layout.addWidget(self.modify_score_button)
self.modify_score_button.setFixedHeight(30)
left_layout.addWidget(self.delete_student_button)
self.delete_student_button.setFixedHeight(30)
right_layout.addWidget(self.view_database_button)
self.view_database_button.setFixedHeight(30)
right_layout.addWidget(self.add_Books)
self.add_Books.setFixedHeight(30)
right_layout.addWidget(self.view_button)
self.view_button.setFixedHeight(30)
# 加载背景图片
palette = QPalette()
background_image = QPixmap("stu_loginsu.png")
palette.setBrush(QPalette.Background, QBrush(background_image))
self.setPalette(palette)
layout.addLayout(left_layout)
layout.addStretch(1) # 在左侧布局后添加伸缩空间
layout.addLayout(right_layout)
self.setLayout(layout)
# 连接信号和槽
# 当点击“修改学生信息”按钮时,调用modify_student_info方法
self.modify_student_button.clicked.connect(self.modify_student_info)
# 当点击“添加成绩”按钮时,调用add_score方法
self.add_score_button.clicked.connect(self.add_score)
self.modify_score_button.clicked.connect(self.update_score)
self.add_Books.clicked.connect(self.add_book)
self.view_button.clicked.connect(self.view_inventory)
self.view_database_button.clicked.connect(self.view_database)
self.delete_student_button.clicked.connect(self.delete_student)
def initDatabase(self):
try:
# 创建或连接到SQLite数据库
self.cursor = self.db_connection.cursor()
# 创建成绩表格(如果尚未创建)
self.cursor.execute('''CREATE TABLE IF NOT EXISTS Scores
(student_id INTEGER NOT NULL, subject TEXT NOT NULL, score REAL NOT NULL,
FOREIGN KEY (student_id) REFERENCES Students(id))''')
self.cursor.execute('''CREATE TABLE IF NOT EXISTS Books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
author TEXT NOT NULL,
index_number TEXT NOT NULL,
publisher TEXT NOT NULL,
quantity INTEGER NOT NULL DEFAULT 0
)''')
self.cursor.execute('''CREATE TABLE IF NOT EXISTS BorrowedBooks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
student_id INTEGER NOT NULL,
book_id INTEGER NOT NULL,
borrow_time TEXT NOT NULL,
FOREIGN KEY(student_id) REFERENCES Students(id),
FOREIGN KEY(book_id) REFERENCES Books(id)
)''')
# 查询表的列信息
self.cursor.execute("PRAGMA table_info(BorrowedBooks)")
columns = self.cursor.fetchall()
# 打印每一列的标签
print("BorrowedBooks 表的列标签为:")
for column in columns:
print(column[1])
# 检查是否存在 borrow_time 列,如果不存在,则添加它
self.cursor.execute("PRAGMA table_info(BorrowedBooks)")
columns = self.cursor.fetchall()
borrow_time_column_exists = any(column[2] == 'borrow_time' for column in columns)
if not borrow_time_column_exists:
self.cursor.execute(
'''ALTER TABLE BorrowedBooks ADD COLUMN borrow_time TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP''')
except Exception as e:
# 处理异常
print(f"An error occurred while initializing the database: {e}")
def check_student_existence(self, student_id):
"""
Check if a student with given ID exists in the database.
"""
try:
query = "SELECT * FROM Students WHERE id=?"
self.cursor.execute(query, (student_id,))
student = self.cursor.fetchone()
if student:
return True
else:
return False
except Exception as e:
print(f"An error occurred while checking student existence: {e}")
return False
def modify_student_info(self):
try:
# 创建一个对话框来显示数据库内容
dialog = QDialog(self)
dialog.setWindowTitle('学生信息修改')
dialog.setGeometry(300, 300, 600, 400)
# 创建一个布局
dialog_layout = QVBoxLayout()
self.ID_label = QLabel('学号:')
self.ID_line_edit = QLineEdit()
self.name_label = QLabel('新姓名:')
self.name_line_edit = QLineEdit()
self.age_label = QLabel('新年龄:')
self.age_line_edit = QLineEdit()
self.gender_label = QLabel('新性别:')
self.gender_combo_box = QComboBox()
self.gender_combo_box.addItem('男')
self.gender_combo_box.addItem('女')
self.sure_button = QPushButton('确认修改')
dialog_layout.addWidget(self.ID_label)
dialog_layout.addWidget(self.ID_line_edit)
dialog_layout.addWidget(self.name_label)
dialog_layout.addWidget(self.name_line_edit)
dialog_layout.addWidget(self.age_label)
dialog_layout.addWidget(self.age_line_edit)
dialog_layout.addWidget(self.gender_label)
dialog_layout.addWidget(self.gender_combo_box)
dialog_layout.addWidget(self.sure_button)
dialog.setLayout(dialog_layout) # 设置对话框的布局
self.sure_button.clicked.connect(
self.on_sure_button_clicked) # Connect the signal without calling the method
# 显示对话框
dialog.exec_()
except Exception as e:
print(f"An error occurred while modifying student information: {e}")
QMessageBox.critical(self, '错误', f'修改学生信息时出错: {e}')
def on_sure_button_clicked(self):
student_id = self.ID_line_edit.text()
self.ID_line_edit.clear()
new_name = self.name_line_edit.text()
self.name_line_edit.clear()
new_age = self.age_line_edit.text()
self.age_line_edit.clear()
new_gender = self.gender_combo_box.currentText()
if not (student_id and new_name and new_age and new_gender):
QMessageBox.warning(self, '警告', '请填写完整信息!')
return
if not self.check_student_existence(student_id):
QMessageBox.warning(self, '警告', '学号不存在,请重新输入!')
return
query = "UPDATE Students SET name=?, age=?, gender=? WHERE id=?"
self.cursor.execute(query, (new_name, new_age, new_gender, student_id))
self.db_connection.commit()
QMessageBox.information(self, '成功', '学生信息修改成功!')
def add_score(self):
try:
# Create a dialog to input score information
dialog = QDialog(self)
dialog.setWindowTitle('添加成绩')
dialog.setGeometry(300, 300, 400, 200)
# Create layout for the dialog
dialog_layout = QVBoxLayout()
# Widgets for inputting score information
id_label = QLabel('学号:')
self.id_line_edit = QLineEdit()
subject_label = QLabel('科目:')
self.subject_line_edit = QLineEdit()
score_label = QLabel('成绩:')
self.score_line_edit = QLineEdit()
# Add widgets to the layout
dialog_layout.addWidget(id_label)
dialog_layout.addWidget(self.id_line_edit)
dialog_layout.addWidget(subject_label)
dialog_layout.addWidget(self.subject_line_edit)
dialog_layout.addWidget(score_label)
dialog_layout.addWidget(self.score_line_edit)
# Button to add the score
add_button = QPushButton('添加成绩')
add_button.clicked.connect(self.on_add_score_clicked)
dialog_layout.addWidget(add_button)
dialog.setLayout(dialog_layout) # Set dialog layout
# 显示对话框
dialog.exec_()
except Exception as e:
print(f"An error occurred while adding score: {e}")
QMessageBox.critical(self, '错误', f'添加成绩时出错: {e}')
def on_add_score_clicked(self):
student_id = self.id_line_edit.text()
subjects = self.subject_line_edit.text().split(',') # Split subjects by comma
scores = self.score_line_edit.text().split(',') # Split scores by comma
if len(subjects) != len(scores):
QMessageBox.warning(self, '警告', '科目和成绩数量不匹配!')
return
if not all(student_id and subject and score for subject, score in zip(subjects, scores)):
QMessageBox.warning(self, '警告', '请填写完整信息!')
return
if not self.check_student_existence(student_id):
QMessageBox.warning(self, '警告', '学号不存在,请重新输入!')
return
try:
scores = [float(score) for score in scores] # Convert scores to float
except ValueError:
QMessageBox.warning(self, '警告', '成绩格式不正确,请输入数字!')
return
# Insert scores into the database
try:
query = "INSERT INTO Scores (student_id, subject, score) VALUES (?, ?, ?)"
data = [(student_id, subject.strip(), score) for subject, score in zip(subjects, scores)]
self.cursor.executemany(query, data)
self.db_connection.commit()
QMessageBox.information(self, '成功', '成绩添加成功!')
except Exception as e:
print(f"An error occurred while inserting scores into database: {e}")
QMessageBox.critical(self, '错误', f'添加成绩时出错: {e}')
def update_score(self):
try:
# 创建一个对话框来显示数据库内容
dialog = QDialog(self)
dialog.setWindowTitle('更新成绩')
# 创建一个布局
dialog_layout = QVBoxLayout()
# 添加控件到布局中
self.student_id_label = QLabel('学号:')
self.student_id_line_edit = QLineEdit()
self.subject_label = QLabel('科目:')
self.subject_line_edit = QLineEdit()
self.new_score_label = QLabel('新成绩:')
self.new_score_line_edit = QLineEdit()
self.update_button = QPushButton('更新')
dialog_layout.addWidget(self.student_id_label)
dialog_layout.addWidget(self.student_id_line_edit)
dialog_layout.addWidget(self.subject_label)
dialog_layout.addWidget(self.subject_line_edit)
dialog_layout.addWidget(self.new_score_label)
dialog_layout.addWidget(self.new_score_line_edit)
dialog_layout.addWidget(self.update_button)
dialog.setLayout(dialog_layout) # 设置对话框的布局
self.update_button.clicked.connect(self.on_update_button_clicked)
dialog.exec_()
# 显示对话框
except Exception as e:
print(f"An error occurred while updating score: {e}")
QMessageBox.critical(self, '错误', f'更新成绩时出错: {e}')
def on_update_button_clicked(self):
student_id = self.student_id_line_edit.text()
self.student_id_line_edit.clear()
subject = self.subject_line_edit.text()
self.subject_line_edit.clear()
new_score = self.new_score_line_edit.text()
self.new_score_line_edit.clear()
if not (student_id and subject and new_score):
QMessageBox.warning(self, '警告', '请填写完整信息!')
return
if not self.check_student_existence(student_id):
QMessageBox.warning(self, '警告', '学号不存在,请重新输入!')
return
try:
new_score = float(new_score) # Convert score to float
except ValueError:
QMessageBox.warning(self, '警告', '成绩格式不正确,请输入数字!')
return
# Update the score in the database
try:
query = "UPDATE Scores SET score=? WHERE student_id=? AND subject=?"
self.cursor.execute(query, (new_score, student_id, subject))
self.db_connection.commit()
QMessageBox.information(self, '成功', '成绩更新成功!')
except Exception as e:
print(f"An error occurred while updating score in database: {e}")
QMessageBox.critical(self, '错误', f'更新成绩时出错: {e}')
def add_book(self):
try:
# 创建一个对话框来输入书籍信息
dialog = QDialog(self)
dialog.setWindowTitle('添加书籍')
# 创建一个布局
dialog_layout = QVBoxLayout()
# 添加控件到布局中
self.title_label = QLabel('书名:')
self.title_line_edit = QLineEdit()
self.author_label = QLabel('作者:')
self.author_line_edit = QLineEdit()
self.index_label = QLabel('索引号:')
self.index_line_edit = QLineEdit()
self.publisher_label = QLabel('出版社:')
self.publisher_line_edit = QLineEdit()
self.quantity_label = QLabel('库存数量:')
self.quantity_spinbox = QSpinBox()
self.quantity_spinbox.setMinimum(1) # 设置库存数量的最小值为1
self.add_button = QPushButton('添加')
dialog_layout.addWidget(self.title_label)
dialog_layout.addWidget(self.title_line_edit)
dialog_layout.addWidget(self.author_label)
dialog_layout.addWidget(self.author_line_edit)
dialog_layout.addWidget(self.index_label)
dialog_layout.addWidget(self.index_line_edit)
dialog_layout.addWidget(self.publisher_label)
dialog_layout.addWidget(self.publisher_line_edit)
dialog_layout.addWidget(self.quantity_label)
dialog_layout.addWidget(self.quantity_spinbox)
dialog_layout.addWidget(self.add_button)
dialog.setLayout(dialog_layout) # 设置对话框的布局
self.add_button.clicked.connect(self.on_add_button_clicked)
dialog.exec_()
except Exception as e:
print(f"An error occurred while adding book: {e}")
QMessageBox.critical(self, '错误', f'添加书籍时出错: {e}')
def on_add_button_clicked(self):
title = self.title_line_edit.text()
author = self.author_line_edit.text()
index_num = self.index_line_edit.text()
publisher = self.publisher_line_edit.text()
quantity = self.quantity_spinbox.value() # 获取库存数量
if not (title and author and index_num and publisher and quantity):
QMessageBox.warning(self, '警告', '请填写完整信息!')
return
try:
# 在数据库中插入书籍信息
query = "INSERT INTO Books (title, author, index_number, publisher, quantity) VALUES (?, ?, ?, ?, ?)"
self.cursor.execute(query, (title, author, index_num, publisher, quantity))
self.db_connection.commit()
QMessageBox.information(self, '成功', '书籍及库存添加成功!')
except Exception as e:
print(f"An error occurred while adding book to database: {e}")
QMessageBox.critical(self, '错误', f'添加书籍时出错: {e}')
def view_inventory(self):
try:
# Create a dialog to display database content
dialog = QDialog(self)
dialog.setWindowTitle('书库内容')
dialog.setGeometry(300, 300, 600, 400) # 设置对话框的大小
# Create a layout
dialog_layout = QVBoxLayout()
# Retrieve book information from the database
cursor = self.db_connection.cursor()
cursor.execute("SELECT id, title, author, index_number, publisher, quantity FROM Books")
books = cursor.fetchall()
# Create a list widget to display book information with checkboxes
list_widget = QListWidget()
for book in books:
item = QListWidgetItem(f"书名: {book[1]}, 作者: {book[2]}, 索引号: {book[3]}, 出版社: {book[4]},库存:{book[5]}")
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
item.setCheckState(Qt.Unchecked)
list_widget.addItem(item)
# Add the list widget to the layout
dialog_layout.addWidget(list_widget)
# Create a button to delete selected book records
delete_button = QPushButton('删除选中记录')
delete_button.clicked.connect(lambda: self.delete_selected_books(list_widget, books))
dialog_layout.addWidget(delete_button)
# Set the layout of the dialog
dialog.setLayout(dialog_layout)
# Display the dialog
dialog.exec_()
except Exception as e:
print(f"An error occurred while viewing book inventory: {e}")
QMessageBox.critical(self, '错误', f'查看书库时出错: {e}')
def delete_selected_books(self, list_widget, books):
try:
cursor = self.db_connection.cursor()
for i in range(list_widget.count()):
if list_widget.item(i).checkState() == Qt.Checked:
book_id = books[i][0]
cursor.execute("DELETE FROM Books WHERE id=?", (book_id,))
self.db_connection.commit()
QMessageBox.information(self, '成功', '选中的书籍记录已删除!')
except Exception as e:
print(f"An error occurred while deleting selected book records: {e}")
QMessageBox.critical(self, '错误', f'删除选中的书籍记录时出错: {e}')
def admin_login(self):
try:
# 创建一个对话框来进行管理员登录
# 创建一个对话框来进行管理员登录
self.dialog = QDialog(self)
self.dialog.setWindowTitle('管理员登录')
self.dialog.setGeometry(300, 300, 500, 400)
# 创建一个垂直布局
main_layout = QVBoxLayout()
# 创建底部的水平布局来放置标签和输入框
bottom_layout = QHBoxLayout()
self.setStyleSheet("""
QLabel {
font-weight: bold;
color: #ffffff; /* 白色字体,以便在蓝色背景上清晰可见 */
background-color: #4CAF50; /* 背景 */
border: 1px solid #9999ff; /* 淡蓝色边框,以增强视觉效果 */
border-radius: 5px; /* 边框圆角 */
padding: 5px 10px; /* 内边距 */
margin: 5px; /* 外边距 */
}
QLineEdit {
border: 1px solid #ccc;
border-radius: 10px;
padding: 5px;
font-size: 12pt;
background-color: #fff;
}
QPushButton {
padding: 5px 10px;
border: none;
border-radius: 8px;
background-color: #4CAF50;
color: white;
font-weight: bold;
}
QPushButton:hover {
background-color: #45a049;
}
""")
self.username_label = QLabel('用户名:')
self.username_line_edit = QLineEdit()
self.username_line_edit.setFixedWidth(70)
self.password_label = QLabel('密码:')
self.password_line_edit = QLineEdit()
self.password_line_edit.setFixedWidth(200)
self.password_line_edit.setEchoMode(QLineEdit.Password) # 设置密码输入框的显示模式为密码模式
self.login_button = QPushButton('登录')
# 将控件添加到顶部的水平布局中
bottom_layout.addWidget(self.username_label)
bottom_layout.addWidget(self.username_line_edit)
bottom_layout.addWidget(self.password_label)
bottom_layout.addWidget(self.password_line_edit)
bottom_layout.addWidget(self.login_button)
# 将顶部的水平布局添加到主垂直布局中
main_layout.addStretch(1)
main_layout.addLayout(bottom_layout)
# 加载背景图片
palette = self.dialog.palette()
background_image = QPixmap("teacher.png") # 保持图片比例
palette.setBrush(QPalette.Background, QBrush(background_image))
self.dialog.setPalette(palette)
# 设置对话框的布局
self.dialog.setLayout(main_layout)
# 连接登录按钮的点击事件
self.login_button.clicked.connect(lambda: self.validate_login(self.dialog))
# 显示对话框
self.dialog.exec_()
except Exception as e:
print(f"An error occurred during admin login: {e}")
def validate_login(self, dialog):
# 验证管理员登录
username = self.username_line_edit.text()
password = self.password_line_edit.text()
try:
query = "SELECT * FROM Admins WHERE username=? AND password=?"
self.cursor.execute(query, (username, password))
admin_record = self.cursor.fetchone()
if admin_record:
QMessageBox.information(self, '成功', '管理员登录成功!')
self.initUI() # 管理员登录成功后初始化管理员管理系统界面
dialog.close() # 关闭登录对话框
else:
QMessageBox.warning(self, '警告', '用户名或密码错误,请重新输入!')
except Exception as e:
print(f"An error occurred during admin login validation: {e}")
def view_database(self):
try:
# 创建一个对话框来显示数据库内容
dialog = QDialog(self)
dialog.setWindowTitle('数据库内容')
# 创建一个布局
dialog_layout = QVBoxLayout()
# 从数据库中检索学生信息
self.cursor.execute("SELECT * FROM Students") # 注意表名大小写
students = self.cursor.fetchall()
# 创建一个列表部件来显示学生信息
list_widget = QListWidget()
for student in students:
# 假设列的顺序是 (id, name, age, gender)
list_widget.addItem(f"ID: {student[0]}, 姓名: {student[1]}, 年龄: {student[2]}, 性别: {student[3]}")
# 将列表部件添加到布局中
dialog_layout.addWidget(list_widget)
# 设置对话框的布局
dialog.setLayout(dialog_layout)
# 显示对话框
dialog.exec_() # 使用 exec_() 而不是 show() 来确保对话框是模态的
except sqlite3.Error as e:
# 处理 SQLite 错误
print(f"数据库错误: {e}")
# 这里可以添加更多的错误处理逻辑,比如显示一个错误消息框
except Exception as e:
# 处理其他类型的异常
print(f"发生了一个错误: {e}")
def delete_student(self):
# Open the delete student dialog
delete_dialog = DeleteStudentDialog(self)
try:
self.cursor.execute("SELECT * FROM students")
students = self.cursor.fetchall()
delete_dialog.set_students(students)
if delete_dialog.exec_() == QDialog.Accepted:
# Get the selected student's ID and delete it from the database
student_id = delete_dialog.get_selected_student_id()
if student_id is not None:
self.cursor.execute("DELETE FROM students WHERE id=?", (student_id,))
self.db_connection.commit()
# self.status_bar.showMessage('学生已删除')
except Exception as e:
# Handle the exception here
print(f"An error occurred: {e}")
self.status_bar.showMessage('删除学生时出错')
finally:
# This block will always be executed, regardless of whether an exception was raised or not
delete_dialog.deleteLater() # Ensure proper cleanup
# def closeEvent(self, event):
# # 在窗口关闭时关闭数据库连接
# self.db_connection.close()
# super().closeEvent(event)
class StudentManagementSystem(QMainWindow):
def __init__(self):
super().__init__()
self.initUI() # 初始化主界面
self.initDatabase() # 初始化数据库
def initUI(self):
# 设置窗口的标题
self.setWindowTitle('学生管理系统')
# 设置窗口的大小
self.setGeometry(300, 300, 600, 400)
# 创建一个中心部件
central_widget = QWidget(self)
self.setCentralWidget(central_widget)
# 创建主垂直布局
main_layout = QVBoxLayout(central_widget)
# 创建水平布局来放置按钮
button_layout = QHBoxLayout()
# 创建按钮并添加到水平布局中
self.add_button = QPushButton('学生注册')
button_layout.addWidget(self.add_button)
self.login_button = QPushButton('学生登陆')
button_layout.addWidget(self.login_button)
self.manager_button = QPushButton('管理员登陆')
button_layout.addWidget(self.manager_button)
# 添加拉伸因子以在按钮和窗口的左侧之间创建空间
main_layout.addStretch(1)
# 将按钮的水平布局添加到主垂直布局的右侧
main_layout.addLayout(button_layout)
# 创建状态栏
self.status_bar = QStatusBar(self)
self.setStatusBar(self.status_bar)
# 加载背景图片
palette = QPalette()
palette.setBrush(QPalette.Background, QBrush(QPixmap("background.png")))
self.setPalette(palette)
# 设置按钮样式
# 定义公共的按钮样式
button_style = """
QPushButton {
background-color: #4CAF50; /* 背景色 */
color: white; /* 文字颜色 */
border: none; /* 无边框 */
border-radius: 5px; /* 圆角 */
padding: 10px 20px; /* 内边距 */
font-size: 16px; /* 字体大小 */
}
QPushButton:hover {
background-color: #45a049; /* 鼠标悬停时的背景色 */
}
QPushButton:pressed {
background-color: #388e3c; /* 按下时的背景色 */
}
"""
# 应用样式到不同的按钮
self.add_button.setStyleSheet(button_style)
self.login_button.setStyleSheet(button_style)
self.manager_button.setStyleSheet(button_style)
# 连接信号和槽
# 当点击“学生注册”按钮时,调用add_student方法
self.add_button.clicked.connect(self.add_student)
# 当点击“学生登陆”按钮时,调用student_login方法
self.login_button.clicked.connect(self.student_login)
# 当点击“管理员登陆”按钮时,调用manager_login方法
self.manager_button.clicked.connect(self.manager_login)
def initDatabase(self):
# 连接到SQLite数据库
self.conn = sqlite3.connect('students.db')
self.cursor = self.conn.cursor()
# 创建表(如果尚未创建)
self.cursor.execute('''CREATE TABLE IF NOT EXISTS Students
(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, gender TEXT NOT NULL)''')
# 创建管理员表格
self.cursor.execute('''CREATE TABLE IF NOT EXISTS Admins (
username TEXT PRIMARY KEY,
password TEXT NOT NULL
)''')
# 检查管理员表是否已有记录,如果没有,则添加默认管理员账户
self.cursor.execute("SELECT * FROM Admins")
admin_record = self.cursor.fetchone()
if not admin_record:
# 添加默认管理员账户
self.cursor.execute("INSERT INTO Admins (username, password) VALUES (?, ?)", ('123', '123456'))
self.conn.commit()
# 学生注册
def add_student(self):
add_dialog = AddStudentDialog(self, db_connection=self.conn)
add_dialog.exec_()
def closeEvent(self, event):
# 在窗口关闭时关闭数据库连接
self.conn.close()
super().closeEvent(event)
# 学生登陆
def student_login(self):
login_dialog = StudentLoginDialog(self, db_connection=self.conn)
login_dialog.exec_()
# 管理员登陆
def manager_login(self):
login_dialog = AdminManagementSystem(self, db_connection=self.conn)
login_dialog.exec_()
if __name__ == '__main__':
app = QApplication(sys.argv) # 管理 GUI 应用程序的控制流和主要设置的类
ex = StudentManagementSystem()
ex.show()
sys.exit(app.exec_())