Python设计图书馆管理系统技术文档(三)

5.设计和代码

5.1 用户登录与注册(MainWindow.py)

  • 主入口程序
    import sys
    from PyQt5.QtWidgets import *
    from PyQt5.QtGui import QIcon
    import qdarkstyle
    from SignIn import SignInWidget
    from SignUp import SignUpWidget
    import sip
    from AdminHome import AdminHome
    from StudentHome import StudentHome
    from changePasswordDialog import changePasswordDialog
    
    
    # 主窗口设计
    class Main(QMainWindow):
        def __init__(self, parent=None):
            """1.初始化主页信息 """
            super(Main, self).__init__(parent)
            # 水平布局
            self.layout = QHBoxLayout()
            # 定义登录窗体控件
            self.widget = SignInWidget()
            # 定义尺寸
            self.resize(900, 600)
            # 定义标题
            self.setWindowTitle("欢迎登陆图书馆管理系统")
            # 居中显示
            self.setCentralWidget(self.widget)
            # 定义菜单栏
            bar = self.menuBar()
            self.Menu = bar.addMenu("菜单栏")
            # 定义菜单栏时的各动作部件,并添加到菜单栏
            self.signUpAction = QAction("注册", self)
            self.changePasswordAction = QAction("修改密码", self)
            self.signInAction = QAction("登录", self)
            self.quitSignInAction = QAction("退出登录", self)
            self.quitAction = QAction("退出", self)
            self.Menu.addAction(self.signUpAction)
            self.Menu.addAction(self.changePasswordAction)
            self.Menu.addAction(self.signInAction)
            self.Menu.addAction(self.quitSignInAction)
            self.Menu.addAction(self.quitAction)
            # 设置菜单栏上各部件触发的有效性
            self.signUpAction.setEnabled(True)
            self.changePasswordAction.setEnabled(True)
            self.signInAction.setEnabled(False)
            self.quitSignInAction.setEnabled(False)
            # 连续三个信号槽,分别连接定位到AdminHome.py(管理员主主页)、StudentHome.py(用户主页)、
            # menuTriggered方法(菜单弹出动作)
            self.widget.is_admin_signal.connect(self.adminSignIn)
            self.widget.is_student_signal[str].connect(self.studentSignIn)
            self.Menu.triggered[QAction].connect(self.menuTriggered)
    
        # 管理员登录页面的弹出和展示效果
        def adminSignIn(self):
            sip.delete(self.widget)
            self.widget = AdminHome()
            self.setCentralWidget(self.widget)
            self.changePasswordAction.setEnabled(False)
            self.signUpAction.setEnabled(True)
            self.signInAction.setEnabled(False)
            self.quitSignInAction.setEnabled(True)
    
        # 用户(学生)登录页面的弹出和展示效果
        def studentSignIn(self, studentId):
            sip.delete(self.widget)
            self.widget = StudentHome(studentId)
            self.setCentralWidget(self.widget)
            self.changePasswordAction.setEnabled(False)
            self.signUpAction.setEnabled(True)
            self.signInAction.setEnabled(False)
            self.quitSignInAction.setEnabled(True)
    
        # 主窗口菜单栏选项的弹出和展示效果
        def menuTriggered(self, q):
            if q.text() == "修改密码":
                changePsdDialog = changePasswordDialog(self)
                changePsdDialog.show()
                changePsdDialog.exec_()
            if q.text() == "注册":
                sip.delete(self.widget)
                self.widget = SignUpWidget()
                self.setCentralWidget(self.widget)
                self.widget.student_signup_signal[str].connect(self.studentSignIn)
                self.signUpAction.setEnabled(False)
                self.changePasswordAction.setEnabled(True)
                self.signInAction.setEnabled(True)
                self.quitSignInAction.setEnabled(False)
            if q.text() == "退出登录" or q.text() == "登录":
                sip.delete(self.widget)
                self.widget = SignInWidget()
                self.setCentralWidget(self.widget)
                self.widget.is_admin_signal.connect(self.adminSignIn)
                self.widget.is_student_signal[str].connect(self.studentSignIn)
                self.signUpAction.setEnabled(True)
                self.changePasswordAction.setEnabled(True)
                self.signInAction.setEnabled(False)
                self.quitSignInAction.setEnabled(False)
            if q.text() == "退出":
                q_app = QApplication.instance()
                q_app.quit()
            return
    
    
    # 主main入口
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        app.setWindowIcon(QIcon("./images/MainWindow_1.png"))
        app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
        mainWindow = Main()
        mainWindow.show()
        sys.exit(app.exec_())
    
    
    
  • 代码分析
    • 主窗口是一个程序开始运行,首先要面对用户的窗口。这个代码已经作了整体的注释,下面再逐个分析。
    • (1)初始化窗口。布局、摆放各种控件。窗体及控件自底层往上层设计,代码自上而下书写。分别是水平布局、总窗体、总窗体尺寸、总窗体标题并居中。菜单栏,菜单栏自上而下的注册、修改密码、退出登录、登录、退出等按键。其中只有注册、修改密码、登录三个是窗体,而退出登录和登录是一个窗体,退出是主程序全部关闭退出的命令。
      在这里插入图片描述
      在这里插入图片描述
      • 初始化模块最后有三个信号槽,分别重定向到登录管理页面、用户页面、菜单栏三个子程序,代码如下:
         # 连续三个信号槽,分别连接定位到AdminHome.py(管理员主主页)、StudentHome.py(用户主页)、
         # menuTriggered方法(菜单弹出动作)
         self.widget.is_admin_signal.connect(self.adminSignIn)
         self.widget.is_student_signal[str].connect(self.studentSignIn)
         self.Menu.triggered[QAction].connect(self.menuTriggered)
        
    • (2)接下来是管理登录( adminSignIn)。在打开管理页面之后,先删除主窗口界面,接着页面居中,密码修改和登录按钮为不可用。
      在这里插入图片描述
    • (3)用户登录页面(studentSignIn)。也是先删除主窗口,接着页面居中,密码修改和登录按钮为不可用。运用效果如图。
      在这里插入图片描述
    • (4)主窗口菜单栏选项(menuTriggered)。
      • 这里面设定四个if语句,其中“退出登录”和“登录”其实是相同代码,我给原代码作了合并处理。
      • 这里第一个if语句是“修改密码”,调用了changePasswordDialog.py里面的changePasswordDialog从而轮到修改密码的对话框控件。
      • 第二个if语句要“注册”,定义了一个注册控件SignUpWidget的实例,然后用了信号槽方法,使得注册完成后,直接跳转到用户界面。而在别的地方注册完成后,还停留在注册对话框。是不一样的。
        self.widget.student_signup_signal[str].connect(self.studentSignIn)
        
      • 第三个if语句是“退出登录”和“登录”。用了or来区分用户分别点击两个对应按钮的反应,其实质都是跳转到登录页面SignIn.py。此处用了两个信号槽方法,用来分别从管理页面AdminHome.py或者用户页面StudentHome.py跳转到用户登录界面。
      • 第四个if语句是“退出”。
    • (5)主入口main程序。加了两句代码,一个是主窗口左上角的图标,另一个是调用系统内置函数,来风格化窗口。代码如下:
      if __name__ == "__main__":
      app = QApplication(sys.argv)
      app.setWindowIcon(QIcon("./images/MainWindow_1.png"))
      app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
      mainWindow = Main()
      mainWindow.show()
      sys.exit(app.exec_())
      
5.1.1 注册文件(SignUp.py)
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import qdarkstyle
from PyQt5.QtSql import *
import hashlib
from PyQt5.QtWidgets import QMessageBox


class SignUpWidget(QWidget):
    student_signup_signal = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.resize(900, 600)
        self.setWindowTitle("欢迎登陆图书馆管理系统")
        self.setUpUI()

    """
    总组件setUpUI---由以下三大块内容完成
    """
    #
    def setUpUI(self):

        """  
            一、垂直布局管理器,放置一个小组件signUpLabel(注册)属类QLabel
        """
        # 1、普通标签signUpLabel(注册)
        self.signUpLabel = QLabel("注   册")
        self.signUpLabel.setAlignment(Qt.AlignCenter)
        self.signUpLabel.setFixedHeight(100)
        # 定义一个字体风格
        font = QFont()
        font.setPixelSize(36)
        self.signUpLabel.setFont(font)

        # 2.垂直布局管理器layout,一行一行来
        # 类QVBowLayout(垂直布局管理器)
        # 然后把第一个组件QLable”注册“放这里面
        self.VBlayout = QVBoxLayout()
        self.VBlayout.addWidget(self.signUpLabel, Qt.AlignHCenter)
        self.setLayout(self.VBlayout)

        """           
            二、定义表单布局管理器formlayout,类QFormLayout(表单式布局器)
            接下来,连续在这个布局控件里面放置4个QLable和4个QLineEdit和1个PushButton
        """

        # 在这里定义一个字体属性,后面继续用
        lineEditFont = QFont()
        lineEditFont.setPixelSize(16)

        # 设置表单布局,包括学号,姓名,密码,确认密码
        self.formlayout = QFormLayout()
        font.setPixelSize(18)
        # Row1————学号
        self.studentIdLabel = QLabel("学    号: ")
        self.studentIdLabel.setFont(font)
        self.studentIdLineEdit = QLineEdit()
        self.studentIdLineEdit.setFixedWidth(160)
        self.studentIdLineEdit.setFixedHeight(32)
        self.studentIdLineEdit.setFont(lineEditFont)
        self.studentIdLineEdit.setMaxLength(10)
        # 一行摆放两列————学号和学号输入框
        self.formlayout.addRow(self.studentIdLabel, self.studentIdLineEdit)

        # Row2————姓名
        self.studentNameLabel = QLabel("姓    名: ")
        self.studentNameLabel.setFont(font)
        self.studentNameLineEdit = QLineEdit()
        self.studentNameLineEdit.setFixedHeight(32)
        self.studentNameLineEdit.setFixedWidth(160)
        self.studentNameLineEdit.setFont(lineEditFont)
        self.studentNameLineEdit.setMaxLength(10)
        # 一行摆放两列————姓名和姓名输入框
        self.formlayout.addRow(self.studentNameLabel, self.studentNameLineEdit)

        lineEditFont.setPixelSize(10)

        # Row3————密码
        self.passwordLabel = QLabel("密    码: ")
        self.passwordLabel.setFont(font)
        self.passwordLineEdit = QLineEdit()
        self.passwordLineEdit.setFixedWidth(160)
        self.passwordLineEdit.setFixedHeight(32)
        self.passwordLineEdit.setFont(lineEditFont)
        self.passwordLineEdit.setEchoMode(QLineEdit.Password)
        self.passwordLineEdit.setMaxLength(16)
        # 一行摆放两列————密码和密码输入框
        self.formlayout.addRow(self.passwordLabel, self.passwordLineEdit)

        # Row4————确认密码
        self.passwordConfirmLabel = QLabel("确认密码: ")
        self.passwordConfirmLabel.setFont(font)
        self.passwordConfirmLineEdit = QLineEdit()
        self.passwordConfirmLineEdit.setFixedWidth(160)
        self.passwordConfirmLineEdit.setFixedHeight(32)
        self.passwordConfirmLineEdit.setFont(lineEditFont)
        self.passwordConfirmLineEdit.setEchoMode(QLineEdit.Password)
        self.passwordConfirmLineEdit.setMaxLength(16)
        # # 一行摆放两列————确认和确认输入框
        self.formlayout.addRow(self.passwordConfirmLabel, self.passwordConfirmLineEdit)

        # Row5————注册
        self.signUpbutton = QPushButton("注 册")
        self.signUpbutton.setFixedWidth(120)
        self.signUpbutton.setFixedHeight(30)
        self.signUpbutton.setFont(font)
        self.formlayout.addRow("", self.signUpbutton)

        """
            三、嵌套各种窗体控件和布局
            1.定义一个放表单的窗体控件widget——widget_form,上面放置布局formlayout(包括里面5个小组件)
            2.接下来对再把widget_form放入一个新定义的水平布局器HLayout里面,居中显示
            3.最后再定义一个窗体控件widget——widget_layout,放到最初的垂直布局器VBlayout里。
            这段代码非常绕,用工具Designer也无法实现层次关系,但是代码正常没有提示报错,逻辑关系如下:
            从底层到顶层为:
            VBlayout(垂直布局)——>widget_Hlayout(控件)——>HLayout(水平布局)——>widget_form(控件)
            ——>formlayout(表单布局)——>四对label和lineEdit,以及一个“空+QPushButton”           
             
            知识链接:
            有些控件或者布局有addLayout和addWidget的函数,但是有些就没有,比如QWidget这个控件只有一个setLayout函数
            但是不关控件或者布局,setlayout只能set一次
            addLayout和addWidget是用来管理布局的,而setLayout是将已设置好的布局应用到控件中去
        """
        widget_form = QWidget()
        widget_form.setFixedWidth(300)
        widget_form.setFixedHeight(250)
        widget_form.setLayout(self.formlayout)
        self.HLayout = QHBoxLayout()
        self.HLayout.addWidget(widget_form, Qt.AlignCenter)
        widget_Hlayout = QWidget()
        widget_Hlayout.setLayout(self.HLayout)
        self.VBlayout.addWidget(widget_Hlayout, Qt.AlignHCenter)

        # 设置验证
        reg1 = QRegExp("PB[0~9]{8}")
        pValidator = QRegExpValidator(self)
        pValidator.setRegExp(reg1)
        self.studentIdLineEdit.setValidator(pValidator)

        reg2 = QRegExp("[a-zA-z0-9]+$")
        pValidator.setRegExp(reg2)
        self.passwordLineEdit.setValidator(pValidator)
        self.passwordConfirmLineEdit.setValidator(pValidator)

        # 连续5个信号槽,分别是注册、学号、姓名、密码、密码确认
        self.signUpbutton.clicked.connect(self.SignUp)
        self.studentIdLineEdit.returnPressed.connect(self.SignUp)
        self.studentNameLineEdit.returnPressed.connect(self.SignUp)
        self.passwordLineEdit.returnPressed.connect(self.SignUp)
        self.passwordConfirmLineEdit.returnPressed.connect(self.SignUp)

    """
        自定义注册函数(槽函数)
    """

    def SignUp(self):
        studentId = self.studentIdLineEdit.text()
        studentName = self.studentNameLineEdit.text()
        password = self.passwordLineEdit.text()
        confirmPassword = self.passwordConfirmLineEdit.text()
        if studentId == "" or studentName == "" or password == "" or confirmPassword == "":
            print(QMessageBox.warning(self, "警告", "输入的内容不能为空,请重新输入", QMessageBox.Yes, QMessageBox.Yes))
            return
        else:
            # 需要处理逻辑,1.账号已存在;2.密码不匹配;3.插入user表
            db = QSqlDatabase.addDatabase("QSQLITE")
            db.setDatabaseName('./db/LibraryManagement.db')
            db.open()
            query = QSqlQuery()
            if confirmPassword != password:
                # 此处和下面一样,参数可以简化不写,但必须两个字符串对应
                print(QMessageBox.warning(self, "嘛意思", "你做着梦录入的吗,两次不一样"))
                return
            elif confirmPassword == password:
                # md5编码
                hl = hashlib.md5()
                hl.update(password.encode(encoding='utf-8'))
                md5password = hl.hexdigest()
                sql = "SELECT * FROM user WHERE StudentId='%s'" % (studentId)
                query.exec_(sql)
                if query.next():
                    print(
                        QMessageBox.warning(self, "傻白甜", "这名字有了,请重新输入", QMessageBox.Yes, QMessageBox.Yes))
                    return
                else:
                    sql = "INSERT INTO user VALUES ('%s','%s','%s',0,0,0)" % (
                        studentId, studentName, md5password)
                    db.exec_(sql)
                    db.commit()
                    print(QMessageBox.information(self, "不错", "您已成功注册账号!", QMessageBox.Yes, QMessageBox.Yes))
                    self.student_signup_signal.emit(studentId)
                db.close()
                return


if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setWindowIcon(QIcon("./images/MainWindow_1.png"))
    app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
    mainWindow = SignUpWidget()
    mainWindow.show()
    sys.exit(app.exec_())

  • 代码分析

    • 重要的有布局、信号槽、数据库sql语句三部分。
    • 这个页面的代码特别是布局,有点绕。图形展示界面setUpUI里面的布局是这样的思路:
      • (1)先设定好四对标签QLabel和单行文本框QLineEdit(包括学号、姓名、密码、确认密码),还有一个按钮QPushButton(注册)。
      • (2)把上面一堆小控件放到表单布局formlayout之后,一系列麻烦的来了。源代码控件变量命名极不规范,为便于理解代码,我都规范处理了,最后布局和图层我还是说不明白,作图如下:
        在这里插入图片描述

    在这里插入图片描述

    • 上面是层层布局的样式,和上面逻辑图对应,由下到上对应由外到内,弄清垂直布局和水平布局,widget窗体控件是为了约束这两个布局的,慢慢理解。

      • 信号槽这里,一共定义了5个,一共槽函数是SignUp(),信号两种内置函数clicked(点击)和returnPressed(返回信号:回车或者离开焦点触发),对应代码如下:
      # 连续5个信号槽,分别是注册、学号、姓名、密码、密码确认
      self.signUpbutton.clicked.connect(self.SignUp)
      self.studentIdLineEdit.returnPressed.connect(self.SignUp)
      self.studentNameLineEdit.returnPressed.connect(self.SignUp)
      self.passwordLineEdit.returnPressed.connect(self.SignUp) 
      self.passwordConfirmLineEdit.returnPressed.connect(self.SignUp)
      
    • 最后一个难点:数据库接口判断。

      • 这部分在SignIn()槽函数中,用到了if控制语句。这里面的判断有三种:输入为空、密码不一致、用户重复。也来图吧,说不明白。

        注册
        信息录入
        确认录入?
        密码一致?
        是否未注册
        注册成功
      • 分析上面的if语句中的逻辑关系,首先里面用到了QMessageBox.warning方法,会弹出消息框。“信息录入”节点之后,而且密码录入两遍一致,则需要调用数据库sql语法的slecet查询语句,如果查询到的记录中,和当前录入的信息一致,则提示当前录入的用户已经注册,需要重新换ID注册。如果查询到数据库中没有用户重复,则调用数据库sql语法的insert插入语句,在表中插入一条用户信息,最后提示注册成功,并且运行(exec)、提交(commit),最最后再用emit传递一下信号与槽函数。

5.1.2 登录文件(SignIn.py)
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import qdarkstyle
import hashlib
from PyQt5.QtSql import *
from PyQt5.QtCore import Qt


class SignInWidget(QWidget):
    """
    为了给登录者进行区分,定义了两个信号
    管理跳转到后台管理页面
    学生跳转到图书馆界面
    (信号槽函数)
    """
    is_admin_signal = pyqtSignal()
    is_student_signal = pyqtSignal(str)

    def __init__(self):
        super(SignInWidget, self).__init__()
        self.resize(900, 600)
        self.setWindowTitle("欢迎使用图书馆管理系统")
        self.setUpUI()

    def setUpUI(self):
        """
        1.总的布局最底层是垂直布局Vlayout
        2.再设定两个水平布局,安排登录窗体大标题和登录小控件的布局Hlayout_title、Hlayout_singIn
        3.再定义表单布局formlayout_signIn,放置上上面小控件的布局
        4.后面连续设定大标题的各级父控件和注册表单布局的父控件
        """

        self.Vlayout = QVBoxLayout(self)
        self.Hlayout_title = QHBoxLayout()
        self.Hlayout_singIn = QHBoxLayout()
        self.formlayout_signIn = QFormLayout()

        # 学号的标签和输入框
        self.label_stuID = QLabel("学号: ")
        labelFont = QFont()
        labelFont.setPixelSize(18)
        lineEditFont = QFont()
        lineEditFont.setPixelSize(16)
        self.label_stuID.setFont(labelFont)
        self.lineEdit_stuID = QLineEdit()
        self.lineEdit_stuID.setFixedWidth(180)
        self.lineEdit_stuID.setFixedHeight(32)
        self.lineEdit_stuID.setFont(lineEditFont)
        self.lineEdit_stuID.setMaxLength(10)
        # 标签和输入框通过表单类添加到一行
        self.formlayout_signIn.addRow(self.label_stuID, self.lineEdit_stuID)

        # 密码和密码输入框
        self.label_pwd = QLabel("密码: ")
        self.label_pwd.setFont(labelFont)
        self.lineEdit_pwd = QLineEdit()
        self.lineEdit_pwd.setFixedWidth(180)
        self.lineEdit_pwd.setFixedHeight(32)
        self.lineEdit_pwd.setMaxLength(16)

        # 设置验证
        # QRegExp 验证用户输入的数据是否有效,
        # 或者是查找并修改文本,或者是提供指定的数据
        reg1 = QRegExp("PB[0~9]{8}")
        pValidator = QRegExpValidator(self)
        pValidator.setRegExp(reg1)
        self.lineEdit_stuID.setValidator(pValidator)

        reg2 = QRegExp("[a-zA-Z0-9]+$")
        pValidator.setRegExp(reg2)
        self.lineEdit_pwd.setValidator(pValidator)

        # 设置密码不可见
        passwordFont = QFont()
        passwordFont.setPixelSize(10)
        self.lineEdit_pwd.setFont(passwordFont)
        self.lineEdit_pwd.setEchoMode(QLineEdit.Password)
        self.formlayout_signIn.addRow(self.label_pwd, self.lineEdit_pwd)
        self.signIn = QPushButton("登 录")
        self.signIn.setFixedWidth(80)
        self.signIn.setFixedHeight(30)
        self.signIn.setFont(labelFont)
        self.formlayout_signIn.addRow("", self.signIn)

        # 添加标题界面
        self.label_title = QLabel("欢迎使用享学图书管理系统")
        fontlabel = QFont()
        fontlabel.setPixelSize(30)
        self.label_title.setFixedWidth(390)
        self.lineEdit_pwd.setFont(fontlabel)
        self.Hlayout_title.addWidget(self.label_title, Qt.AlignCenter)

        # 整体的布局
        # QWidget 窗口控制一个程序拥有一个窗口或者多个窗口
        # 每个窗口都有多个控件
        # 所有的窗口和控件都是直接或者间接继承自QWidget
        self.widget_title = QWidget()
        self.widget_title.setLayout(self.Hlayout_title)

        self.widget_signIn = QWidget()
        self.widget_signIn.setFixedWidth(300)
        self.widget_signIn.setFixedHeight(150)
        self.widget_signIn.setLayout(self.formlayout_signIn)
        self.Hlayout_singIn.addWidget(self.widget_signIn, Qt.AlignCenter)

        self.widgetBottom = QWidget()
        self.widgetBottom.setLayout(self.Hlayout_singIn)
        self.Vlayout.addWidget(self.widget_title)
        self.Vlayout.addWidget(self.widgetBottom, Qt.AlignTop)

        # 信号与槽,设定链接到用户和管理的对应页面
        self.signIn.clicked.connect(self.signInCheck)
        self.lineEdit_pwd.returnPressed.connect(self.signInCheck)
        self.lineEdit_stuID.returnPressed.connect(self.signInCheck)

    def signInCheck(self):
        studentId = self.lineEdit_stuID.text()
        password = self.lineEdit_pwd.text()
        if studentId == "" or password == "":
            print(QMessageBox.warning(self, "警告", "学号和密码不可为空!", QMessageBox.Yes, QMessageBox.Yes))
            return
        # 打开数据库连接
        db = QSqlDatabase.addDatabase("QSQLITE")
        db.setDatabaseName('./db/LibraryManagement.db')
        db.open()
        query = QSqlQuery()
        sql = "SELECT * FROM user WHERE StudentId='%s'" % (studentId)
        query.exec_(sql)
        db.close()

        hl = hashlib.md5()
        hl.update(password.encode(encoding='utf-8'))
        if not query.next():
            print(QMessageBox.information(self, "提示", "该账号不存在!", QMessageBox.Yes, QMessageBox.Yes))
        else:
            if studentId == query.value(0) and hl.hexdigest() == query.value(2):
                # 如果是管理员
                if query.value(3) == 1:
                    self.is_admin_signal.emit()
                else:
                    self.is_student_signal.emit(studentId)
            else:
                print(QMessageBox.information(self, "提示", "密码错误!", QMessageBox.Yes, QMessageBox.Yes))
        return


if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setWindowIcon(QIcon("./images/MainWindow_1.png"))
    app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
    mainMindow = SignInWidget()
    mainMindow.show()
    sys.exit(app.exec_())


  • 代码分析
    • 重要的还是布局,布局。

    • 这个页面的代码布局命名更加不规范,统一改成看词识意的名字了。图形展示界面setUpUI里面的布局是这样的:

      • (1)总的布局最底层是垂直布局Vlayout。
      • (2)再设定两个水平布局,安排登录窗体大标题和登录小控件的布局Hlayout_title、Hlayout_singIn
      • (3)再定义表单布局formlayout_signIn,放置上设定好的两对标签QLabel和单行文本框QLineEdit(包括学号、密码),再设置上按钮(登录)。
      • (4)后面连续设定大标题的各级父控件和注册表单布局的父控件,说不清楚,作图如下
        在这里插入图片描述
    • 其他如学号、密码的定义与设置,大标题的位置和规范,就显得好理解多了。

    • 这个页面的代码,又定义了一个槽函数signInCheck(),前面代码最后,有信号连接到这个函数。代码如下:

      # 信号与槽,设定链接到用户和管理的对应页面
      self.signIn.clicked.connect(self.signInCheck)
      self.lineEdit_pwd.returnPressed.connect(self.signInCheck)
      self.lineEdit_stuID.returnPressed.connect(self.signInCheck)
      
    • signInCheck()里面的功能有:用户及密码的验证判断,以及跳转管理页面和用户页面的判断。

      • (1)首先查看判断表单控件内是否有信息录入,不可为空。
      • (2)然后打开数据库连接,查询验证录入的用户ID是否在数据库中存在;若存在再判断用户名和密码是否一致,不一致则密码错误重新录入。这些成立了,最后判断是不是管理员登录。最最后不忘emit(),再把信号槽提交运行。说不清楚,作图。
      • 逻辑图一
      Created with Raphaël 2.3.0 开始 信息录入 是否录入信息 进入下一步 yes no
      • 逻辑图二
        Created with Raphaël 2.3.0 开始 信息录入 帐号是否存在 是否管理员 进入管理页面 普通用户界面 yes no yes no
5.1.3 密码修改(changePasswordDialog.py)
import hashlib
import sys

import qdarkstyle
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSql import *
from PyQt5.QtWidgets import *


class changePasswordDialog(QDialog):
    def __init__(self, parent=None):
        super(changePasswordDialog, self).__init__(parent)
        self.setWindowModality(Qt.WindowModal)
        self.setWindowTitle("修改密码")
        self.setUpUI()

    def setUpUI(self):
        self.resize(300, 280)
        self.layout = QFormLayout()
        self.setLayout(self.layout)

        # 自上而下,5个标签
        self.titlelabel = QLabel(" 修改密码")
        self.studentIdLabel = QLabel("学    号:")
        # self.studentNameLabel=QLabel("姓    名:")
        self.oldPasswordLabel = QLabel("旧 密 码:")
        self.passwordLabel = QLabel("新 密 码:")
        self.confirmPasswordLabel = QLabel("确认密码:")

        # 自上而下,4个文本框
        self.studentIdEdit = QLineEdit()
        # self.studentNameEdit=QLineEdit()
        self.oldPasswordEdit = QLineEdit()
        self.passwordEdit = QLineEdit()
        self.confirmPasswordEdit = QLineEdit()

        # “确认修改”按钮
        self.changePasswordButton = QPushButton("确认修改")
        self.changePasswordButton.setFixedWidth(140)
        self.changePasswordButton.setFixedHeight(32)

        # 在表单布局放置以上小控件
        self.layout.addRow("", self.titlelabel)
        self.layout.addRow(self.studentIdLabel, self.studentIdEdit)
        # self.layout.addRow(self.studentNameLabel,self.studentNameEdit)
        self.layout.addRow(self.oldPasswordLabel, self.oldPasswordEdit)
        self.layout.addRow(self.passwordLabel, self.passwordEdit)
        self.layout.addRow(self.confirmPasswordLabel, self.confirmPasswordEdit)
        self.layout.addRow("", self.changePasswordButton)

        font = QFont()
        font.setPixelSize(20)
        self.titlelabel.setFont(font)
        font.setPixelSize(16)
        self.studentIdLabel.setFont(font)
        # self.studentNameLabel.setFont(font)
        self.oldPasswordLabel.setFont(font)
        self.passwordLabel.setFont(font)
        self.confirmPasswordLabel.setFont(font)

        font.setPixelSize(16)
        self.studentIdEdit.setFont(font)
        self.changePasswordButton.setFont(font)
        # self.studentNameEdit.setFont(font)
        font.setPixelSize(10)
        self.oldPasswordEdit.setFont(font)
        self.passwordEdit.setFont(font)
        self.confirmPasswordEdit.setFont(font)

        self.titlelabel.setMargin(8)
        self.layout.setVerticalSpacing(10)

        # 设置长度
        self.studentIdEdit.setMaxLength(10)
        self.oldPasswordEdit.setMaxLength(16)
        self.passwordEdit.setMaxLength(16)
        self.confirmPasswordEdit.setMaxLength(16)
        # 设置密码掩膜
        self.oldPasswordEdit.setEchoMode(QLineEdit.Password)
        self.passwordEdit.setEchoMode(QLineEdit.Password)
        self.confirmPasswordEdit.setEchoMode(QLineEdit.Password)

        # 设置校验
        reg = QRegExp("PB[0~9]{8}")
        pValidator = QRegExpValidator(self)
        pValidator.setRegExp(reg)
        self.studentIdEdit.setValidator(pValidator)

        reg = QRegExp("[a-zA-z0-9]+$")
        pValidator.setRegExp(reg)
        self.oldPasswordEdit.setValidator(pValidator)
        self.passwordEdit.setValidator(pValidator)
        self.confirmPasswordEdit.setValidator(pValidator)

        # 设置信号与槽
        self.changePasswordButton.clicked.connect(self.changePasswordButtonClicked)

    def changePasswordButtonClicked(self):
        studentId = self.studentIdEdit.text()
        oldPassword = self.oldPasswordEdit.text()
        password = self.passwordEdit.text()
        confirmPassword = self.confirmPasswordEdit.text()
        if studentId == "" or oldPassword == "" or password == "" or confirmPassword == "":
            print(QMessageBox.warning(self, "警告", "输入不可为空,请重新输入", QMessageBox.Yes, QMessageBox.Yes))
            return
        db = QSqlDatabase.addDatabase("QSQLITE")
        db.setDatabaseName('./db/LibraryManagement.db')
        db.open()
        query = QSqlQuery()
        sql = "SELECT * FROM User WHERE StudentId='%s'" % studentId
        query.exec_(sql)
        # 如果用户不存在
        if not query.next():
            print(QMessageBox.warning(self, "警告", "该用户不存在,请重新输入", QMessageBox.Yes, QMessageBox.Yes))
            self.studentIdEdit.clear()
            return
            # 如果密码错误
        hl = hashlib.md5()
        hl.update(oldPassword.encode(encoding='utf-8'))
        md5password = hl.hexdigest()
        sql = "SELECT * FROM User WHERE Password='%s' AND StudentId='%s'" % (md5password, studentId)
        query.exec_(sql)
        if not query.next():
            print(QMessageBox.warning(self, "警告", "原密码输入错误,请重新输入", QMessageBox.Yes, QMessageBox.Yes))
            self.oldPasswordEdit.clear()
            return
        # 密码与确认密码不同
        if password != confirmPassword:
            print(QMessageBox.warning(self, "警告", "两次输入密码不同,请确认输入", QMessageBox.Yes, QMessageBox.Yes))
            self.passwordEdit.clear()
            self.confirmPasswordEdit.clear()
            return
        # 修改密码
        hl = hashlib.md5()
        hl.update(password.encode(encoding='utf-8'))
        md5password = hl.hexdigest()
        sql = "UPDATE User SET Password='%s' WHERE StudentId='%s'" % (md5password, studentId)
        query.exec_(sql)
        db.commit()
        QMessageBox.information(self, "提醒", "修改密码成功,请登录系统!", QMessageBox.Yes, QMessageBox.Yes)
        self.close()
        return


if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setWindowIcon(QIcon("./images/MainWindow_1.png"))
    app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
    mainWindow = changePasswordDialog()
    mainWindow.show()
    sys.exit(app.exec_())

  • 代码分析
    • 这个对话框不算大,相对来说,代码却有点长,其实比前面三个要简单一些。

    • 初始化就不说了,还是setUpUI()函数的布局,最底层只用了一个表单布局,然后自上而下布局为:

      • (1)“” + 修改密码Label
      • (2)学号Label + 学号LineEdit
      • (3)旧密码Label + 旧密码LineEdit
      • (4)新密码Label + 新密码LineEdit
      • (5)确认密码Label + 确认密码LineEdit
      • (6)“” + 修改密码PushButton,如图说明。
      • 至于各标签和文本框的风格定义,代码比较多,不过不麻烦。
        在这里插入图片描述
    • 然后是密码校验,代码看上面程序。之后还是绑定信号与槽。

      self.changePasswordButton.clicked.connect(self.changePasswordButtonClicked)
      
    • 最后就是自定义槽函数changePasswordButtonClicked()的说明。

    • 首先,也是输入的信息不能为空。

    • 逻辑图一

      Created with Raphaël 2.3.0 开始 信息录入 是否录入信息 进入下一步 yes no
    • 其次,连接数据库,再用select语句查询要修改密码的用户ID是否存在,然后展开if语句进行条件判断。

    • 逻辑图二

      Created with Raphaël 2.3.0 开始 信息录入 帐号是否存在 进入下一步 yes no
    • 逻辑图二

      Created with Raphaël 2.3.0 开始 录入原密码 原密码是否正确 进入下一步 yes no
    • 逻辑图三

      开始
      信息录入
      录入新密码
      确认新密码
      密码一致?
      修改密码成功
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山哥ol

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值