学生管理系统(基于Python中的sqlite和qt)

使用PyQt5库构建的图形用户界面(GUI)应用程序,它包含了学生管理系统和管理员管理系统。这个应用程序允许用户进行学生信息的注册、登录、查看、修改和删除,以及书籍库存的管理等功能。

应用概述

  • 名称:学生管理系统
  • 开发环境:Python,使用PyQt5库
  • 功能
    • 学生注册
    • 学生登录
    • 成绩查看
    • 书籍借阅和归还
    • 管理员登录
    • 学生信息管理(包括修改和删除)
    • 成绩添加和更新
    • 图书库存管理(添加、查看和删除)

主要类和功能

  1. DeleteStudentDialog:用于删除学生信息的对话框。
  2. AddStudentDialog:用于添加学生信息的对话框,包含学号、姓名、年龄和性别的输入。
  3. StudentLoginDialog:学生登录对话框,允许学生查看成绩和借阅书籍。
  4. AdminManagementSystem:管理员管理系统对话框,提供学生信息管理、成绩管理、书籍库存管理等功能。
  5. StudentManagementSystem:主窗口类,提供学生注册、登录和管理员登录的入口。

数据库操作

  • 使用SQLite数据库存储学生、管理员和书籍信息。
  • 数据库连接在StudentManagementSystem类中初始化,并在关闭事件中关闭。
  • 使用cursor对象执行SQL语句进行数据库操作。

界面设计

  • 应用使用了多个对话框(QDialog)来收集用户输入或显示信息。
  • 使用了QLineEditQLabelQPushButtonQGridLayout等组件来设计界面。
  • 通过QHBoxLayoutQVBoxLayout来组织界面布局。

事件处理

  • 通过.clicked.connect()方法将按钮点击事件连接到相应的处理函数。
  • 例如,登录按钮点击会触发验证登录信息的函数。

样式定制

  • 使用setStyleSheet()方法为不同的GUI组件设置样式。

异常处理

  • 应用尝试捕获和处理sqlite3.Error和其他可能发生的异常。

运行条件

  • 需要有Python环境和PyQt5库安装。

代码入口

  • 程序的入口点是if __name__ == '__main__':部分,创建了QApplication实例和主窗口StudentManagementSystem,并进入事件循环。

结论

这段代码提供了一个完整的学生管理系统的实现,包括前台的学生交互界面和后台的数据库管理。它是一个典型的PyQt5应用程序,展示了如何使用事件驱动编程来创建交互式界面。

结果展示

图 1主界面
图 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_())

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值