《快速掌握PyQt5》第五章 完善登录框小程序

第五章 完善登录框小程序

5.1 登录界面布局

5.2 完善单行文本输入框和按钮功能

5.3 完善注册界面布局及功能

5.4 整合登录界面和注册界面

5.5 小结


《快速掌握PyQt5》专栏已整理成书出版,书名为《PyQt编程快速上手》,详情请见该链接。感谢大家一直以来的支持!祝大家PyQt用得越来越顺!

在这一章中,我们会结合前面所学的知识来完善登录框小程序。

为保证代码敲击畅通,可以先引入该程序用到的模块和控件:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QLabel, QLineEdit, QPushButton, \
    QGridLayout, QVBoxLayout, QHBoxLayout, QMessageBox

5.1 登录界面布局

首先完成登录界面布局,请看下方代码:

class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 100)

        self.user_label = QLabel('Username:', self)
        self.pwd_label = QLabel('Password:', self)
        self.user_line = QLineEdit(self)
        self.pwd_line = QLineEdit(self)
        self.login_button = QPushButton('Log in', self)
        self.signin_button = QPushButton('Sign in', self)

        self.grid_layout = QGridLayout()
        self.h_layout = QHBoxLayout()
        self.v_layout = QVBoxLayout()

        self.layout_init()

    def layout_init(self):
        self.grid_layout.addWidget(self.user_label, 0, 0, 1, 1)
        self.grid_layout.addWidget(self.user_line, 0, 1, 1, 1)
        self.grid_layout.addWidget(self.pwd_label, 1, 0, 1, 1)
        self.grid_layout.addWidget(self.pwd_line, 1, 1, 1, 1)
        self.h_layout.addWidget(self.login_button)
        self.h_layout.addWidget(self.signin_button)
        self.v_layout.addLayout(self.grid_layout)
        self.v_layout.addLayout(self.h_layout)

        self.setLayout(self.v_layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

程序首先将窗口的宽设为300,长设为100。接着再实例化了几个控件:两个文本标签、两个单行文本输入框和两个按钮。然后搭配使用网格布局管理器、水平布局管理器和垂直布局管理器来完成整个界面的布局。相信看过前面章节的小伙伴已经可以理解上方代码的意思了,这里就不再详细解释。

这里有一点需要注意一下,我把布局管理专门放在了一个函数中layout_init(),然后只用在初始化函数中加上layout_init()中就行。把对不同控件的操作分开来放在相应的函数中,这样写不仅可以让代码更加清晰明了,也方便日后维护。

此时程序运行截图如下:

5.2 完善单行文本输入框和按钮功能

该步骤要完成的结果截图如下:

单行文本输入框中有浅灰色的提示文字,Log in按钮刚开始无法点击,只能等两个输入框中都有文本输入的时候才可以进行点击。

首先对输入框功能进行完善。

def lineedit_init(self):
    self.user_line.setPlaceholderText('Please enter your username')
    self.pwd_line.setPlaceholderText('Please enter your password')

    self.user_line.textChanged.connect(self.check_input_func)
    self.pwd_line.textChanged.connect(self.check_input_func)

在未输入前,我们有会看到输入框上就已经有了一行浅灰色的提示文字,就像下面这种:

但点击的话浅灰色的文字就会不见:

这种功能就是通过setPlaceholderText()方法来实现的。在这里还进行了信号和槽的连接,将QLineEdit的textChanged()信号连接到一个自定义的槽self.check_input_func上。textChanged()信号会在输入框中文本发生变化的时候发出, 所以槽函数的任务就是判断两个输入框是否都有文字了:

def check_input_func(self):
    if self.user_line.text() and self.pwd_line.text():
        self.login_button.setEnabled(True)
    else:
        self.login_button.setEnabled(False)

如果账号框和密码框都有文本(通过text()方法获取输入框文本),那就使登录按钮可用(setEnabled(True)),否则登录按钮不可用。

接下来对按钮进行完善:

def pushbutton_init(self):
    self.login_button.setEnabled(False)

使刚开始显示的登录按钮不可用,只有等账号框和密码框都有文本的时候才能用(上面的槽函数)。

当我们点击登录按钮的时候,账号框和密码框都有文本了,那点击后肯定是要验证账号密码是否正确:

def pushbutton_init(self):
    self.login_button.setEnabled(False)
    self.login_button.clicked.connect(self.check_login_func)

所以我们将登录按钮的clicked信号和一个用于检查账号密码是否正确的自定义槽函数连接起来:

首先我们在程序的最开始处定义一个全局变量USER_PWD:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QLabel, QLineEdit, QPushButton, \
    QGridLayout, QVBoxLayout, QHBoxLayout, QMessageBox

USER_PWD = {
        'la_vie': 'password'
    }

该字典的键'la_vie'就是当作账号,值‘password’就当作密码(之后复杂的程序会使用数据库,这里就先简单定义一个全局变量来使用)。

然后定义检查账号密码的槽函数:

def check_login_func(self):
    if USER_PWD.get(self.user_line.text()) == self.pwd_line.text():
        QMessageBox.information(self, 'Information', 'Log in Successfully!')
    else:
        QMessageBox.critical(self, 'Wrong', 'Wrong Username or Password!')

    self.user_line.clear()
    self.pwd_line.clear()

将账号框的文本当作get()的参数来获取值,然后跟密码框的文本进行比较,若相同则显示信息框提示登录成功,否则显示账号或密码错误。最后无论成功还是失败,都会用clear()方法来清空账号框和密码框。

最后将self.lineedit_init()和self.pushbutton_init()放在类的初始化函数__init__()中:

class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 100)

        self.user_label = QLabel('Username:', self)
        self.pwd_label = QLabel('Password:', self)
        self.user_line = QLineEdit(self)
        self.pwd_line = QLineEdit(self)
        self.login_button = QPushButton('Log in', self)
        self.signin_button = QPushButton('Sign in', self)

        self.grid_layout = QGridLayout()
        self.h_layout = QHBoxLayout()
        self.v_layout = QVBoxLayout()

        self.lineedit_init()            # 单行文本输入框
        self.pushbutton_init()          # 按钮
        self.layout_init()

此时程序运行截图如下:

输入la_vie和password,点击Log in按钮,则显示信息框提示登录成功。

输入一个错误的账号或错误的密码,就会显示错误框提示账号或密码错误:

点击OK后,账号框和密码框文本都被清空,恢复原状:

5.3 完善注册界面布局及功能

接下来就是要完善Sign in按钮这个功能,这里我们想的是点击这个按钮后,会出现一个新的界面用于注册,即下方截图所示:

可以看出该界面一共是由三个QLabel、三个QLineEdit和一个QPushButton组成的,那首先就来完成界面布局:

class SigninPage(QDialog):
    def __init__(self):
        super(SigninPage, self).__init__()
        self.signin_user_label = QLabel('Username:', self)
        self.signin_pwd_label = QLabel('Password:', self)
        self.signin_pwd2_label = QLabel('Password:', self)
        self.signin_user_line = QLineEdit(self)
        self.signin_pwd_line = QLineEdit(self)
        self.signin_pwd2_line = QLineEdit(self)
        self.signin_button = QPushButton('Sign in', self)

        self.user_h_layout = QHBoxLayout()
        self.pwd_h_layout = QHBoxLayout()
        self.pwd2_h_layout = QHBoxLayout()
        self.all_v_layout = QVBoxLayout()

        self.layout_init()

    def layout_init(self):
        self.user_h_layout.addWidget(self.signin_user_label)
        self.user_h_layout.addWidget(self.signin_user_line)
        self.pwd_h_layout.addWidget(self.signin_pwd_label)
        self.pwd_h_layout.addWidget(self.signin_pwd_line)
        self.pwd2_h_layout.addWidget(self.signin_pwd2_label)
        self.pwd2_h_layout.addWidget(self.signin_pwd2_line)

        self.all_v_layout.addLayout(self.user_h_layout)
        self.all_v_layout.addLayout(self.pwd_h_layout)
        self.all_v_layout.addLayout(self.pwd2_h_layout)
        self.all_v_layout.addWidget(self.signin_button)

        self.setLayout(self.all_v_layout)

这里我们新写一个类,并继承于QDialog(另一个毛坯房)。QDialog就是指对话框,我们平时在软件中点击“打开”或“另存为”而出现的文件对话框就是其中一种。当然你这里也可以同样继承于QWidget,但是QDialog中有一个方法是QWidget所不具有的,稍后来讲述。

上面的代码不再详细解释,相信大家可以看懂了。

首先同样将Sign in按钮设为不可用(setEnabled(False)),并且只有当三个输入框中都有文本的时候,才会启用这个按钮。原理跟之前讲的一样:

def lineedit_init(self):
    self.signin_user_line.textChanged.connect(self.check_input_func)
    self.signin_pwd_line.textChanged.connect(self.check_input_func)
    self.signin_pwd2_line.textChanged.connect(self.check_input_func)

在lineedit_init()中我们将三个输入框的textChanged()信号跟自定义的check_input_func()槽函数进行连接;

def check_input_func(self):
    if self.signin_user_line.text() and self.signin_pwd_line.text() and self.signin_pwd2_line.text():
        self.signin_button.setEnabled(True)
    else:
        self.signin_button.setEnabled(False)

在槽函数中我们判断三个输入框是否都有文本,有的话则将按钮启用,否则禁用;

def pushbutton_init(self):
    self.signin_button.setEnabled(False)
    self.signin_button.clicked.connect(self.check_signin_func)

然后在pushbutton_init()中先将sign in按钮设为禁用状态,然后将clicked()信号和之后自定义的check_signin_func()槽函数连接起来。因为在点击注册按钮的时候我们要对输入的文本内容进行检查,看符不符合要求;

def check_signin_func(self):
    if self.signin_pwd_line.text() != self.signin_pwd2_line.text():
        QMessageBox.critical(self, 'Wrong', 'Two Passwords Typed Are Not Same!')
    elif self.signin_user_line.text() not in USER_PWD:
        USER_PWD[self.signin_user_line.text()] = self.signin_pwd_line.text()
        QMessageBox.information(self, 'Information', 'Register Successfully')
        self.close()
    else:
        QMessageBox.critical(self, 'Wrong', 'This Username Has Been Registered!')

    self.signin_user_line.clear()
    self.signin_pwd_line.clear()
    self.signin_pwd2_line.clear()

首先判断两次密码输入框输入的文本是否一致,若不相同的话,则显示错误框提示;当然我们还要对要注册的账号进行判断,如果在字典相对应的键,则说明该账号并没有被注册过,接着将要注册的账号和密码放进字典中,并显示信息框提示注册成功。self.close()是指关闭对话框自身,也就是在信息框按钮被按下去关闭之后,注册界面的对话框也要一起关闭。最后一种情况就是账号已经被注册过了,于是显示错误框来进行提示。

无论哪种情况,最后都会将三个输入框的文本清空掉。

那么最后将self.lineedit_init()和self.pushbutton_init()放在类的初始化函数__init__()中:

class SigninPage(QDialog):
    def __init__(self):
        super(SigninPage, self).__init__()
        self.signin_user_label = QLabel('Username:', self)
        self.signin_pwd_label = QLabel('Password:', self)
        self.signin_pwd2_label = QLabel('Password:', self)
        self.signin_user_line = QLineEdit(self)
        self.signin_pwd_line = QLineEdit(self)
        self.signin_pwd2_line = QLineEdit(self)
        self.signin_button = QPushButton('Sign in', self)

        self.user_h_layout = QHBoxLayout()
        self.pwd_h_layout = QHBoxLayout()
        self.pwd2_h_layout = QHBoxLayout()
        self.all_v_layout = QVBoxLayout()

        self.lineedit_init()            # 单行文本输入框
        self.pushbutton_init()          # 按钮
        self.layout_init()

5.4 整合登录界面和注册界面

但是此时运行程序点击登录界面上的sign in按钮的话,注册界面是显示不出来的,所以我们要将登录界面sign in按钮的clicked()信号和一个自定义的用来显示注册界面的槽函数连接起来:

class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 100)

        self.user_label = QLabel('Username:', self)
        self.pwd_label = QLabel('Password:', self)
        self.user_line = QLineEdit(self)
        self.pwd_line = QLineEdit(self)
        self.login_button = QPushButton('Log in', self)
        self.signin_button = QPushButton('Sign in', self)

        self.grid_layout = QGridLayout()
        self.h_layout = QHBoxLayout()
        self.v_layout = QVBoxLayout()

        self.lineedit_init()
        self.pushbutton_init()
        self.layout_init()
        self.signin_page = SigninPage()     # 实例化SigninPage()

首先我们在Demo的初始化函数中先实例化了SigninPage;

def pushbutton_init(self):
    self.login_button.setEnabled(False)
    self.login_button.clicked.connect(self.check_login_func)
    self.signin_button.clicked.connect(self.show_signin_page_func)

接着在处理按钮的函数中将sign in按钮的clicked信号和show_signin_page_func()槽函数进行连接; 

def show_signin_page_func(self):
    self.signin_page.exec_()

在槽函数中,我们用exec_方法来执行注册界面。为什么要使用exec_而不是show()?下面来详细解释下这两个方法的区别:

若使用exec_()的话,那么显示出来的注册界面就是模态的,意思就是当前只能对该注册界面进行操作,只有关闭了该界面才能对其他界面进行操作;若使用show()的话,那注册界面就是非模态的,则在显示了注册界面后,还能同时对登录界面进行操作(QDialog有exec_()方法,而QWidget没有)。

此时运行截图如下:

点击登录界面的Sign in,显示注册界面,然后输入账号密码,若没有问题,则显示注册成功;

若两次密码输入不一致,则显示错误框提示; 

若用户名已经被注册过了,则显示错误框提示。 

这里为了方便演示,所以密码框输入的时候都没有用原点替代,我们可以对输入框使用setEchoMode(QLineEdit.Password)方法来完成此功能:

最终完整的代码如下:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QLabel, QLineEdit, QPushButton, \
    QGridLayout, QVBoxLayout, QHBoxLayout, QMessageBox

USER_PWD = {
        'la_vie': 'password'
    }


class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(300, 100)

        self.user_label = QLabel('Username:', self)
        self.pwd_label = QLabel('Password:', self)
        self.user_line = QLineEdit(self)
        self.pwd_line = QLineEdit(self)
        self.login_button = QPushButton('Log in', self)
        self.signin_button = QPushButton('Sign in', self)

        self.grid_layout = QGridLayout()
        self.h_layout = QHBoxLayout()
        self.v_layout = QVBoxLayout()

        self.lineedit_init()
        self.pushbutton_init()
        self.layout_init()
        self.signin_page = SigninPage()     # 实例化SigninPage()

    def layout_init(self):
        self.grid_layout.addWidget(self.user_label, 0, 0, 1, 1)
        self.grid_layout.addWidget(self.user_line, 0, 1, 1, 1)
        self.grid_layout.addWidget(self.pwd_label, 1, 0, 1, 1)
        self.grid_layout.addWidget(self.pwd_line, 1, 1, 1, 1)
        self.h_layout.addWidget(self.login_button)
        self.h_layout.addWidget(self.signin_button)
        self.v_layout.addLayout(self.grid_layout)
        self.v_layout.addLayout(self.h_layout)

        self.setLayout(self.v_layout)

    def lineedit_init(self):
        self.user_line.setPlaceholderText('Please enter your username')
        self.pwd_line.setPlaceholderText('Please enter your password')
        self.pwd_line.setEchoMode(QLineEdit.Password)

        self.user_line.textChanged.connect(self.check_input_func)
        self.pwd_line.textChanged.connect(self.check_input_func)

    def pushbutton_init(self):
        self.login_button.setEnabled(False)
        self.login_button.clicked.connect(self.check_login_func)
        self.signin_button.clicked.connect(self.show_signin_page_func)

    def check_login_func(self):
        if USER_PWD.get(self.user_line.text()) == self.pwd_line.text():
            QMessageBox.information(self, 'Information', 'Log in Successfully!')
        else:
            QMessageBox.critical(self, 'Wrong', 'Wrong Username or Password!')

        self.user_line.clear()
        self.pwd_line.clear()

    def show_signin_page_func(self):
        self.signin_page.exec_()

    def check_input_func(self):
        if self.user_line.text() and self.pwd_line.text():
            self.login_button.setEnabled(True)
        else:
            self.login_button.setEnabled(False)


class SigninPage(QDialog):
    def __init__(self):
        super(SigninPage, self).__init__()
        self.signin_user_label = QLabel('Username:', self)
        self.signin_pwd_label = QLabel('Password:', self)
        self.signin_pwd2_label = QLabel('Password:', self)
        self.signin_user_line = QLineEdit(self)
        self.signin_pwd_line = QLineEdit(self)
        self.signin_pwd2_line = QLineEdit(self)
        self.signin_button = QPushButton('Sign in', self)

        self.user_h_layout = QHBoxLayout()
        self.pwd_h_layout = QHBoxLayout()
        self.pwd2_h_layout = QHBoxLayout()
        self.all_v_layout = QVBoxLayout()

        self.lineedit_init()
        self.pushbutton_init()
        self.layout_init()

    def layout_init(self):
        self.user_h_layout.addWidget(self.signin_user_label)
        self.user_h_layout.addWidget(self.signin_user_line)
        self.pwd_h_layout.addWidget(self.signin_pwd_label)
        self.pwd_h_layout.addWidget(self.signin_pwd_line)
        self.pwd2_h_layout.addWidget(self.signin_pwd2_label)
        self.pwd2_h_layout.addWidget(self.signin_pwd2_line)

        self.all_v_layout.addLayout(self.user_h_layout)
        self.all_v_layout.addLayout(self.pwd_h_layout)
        self.all_v_layout.addLayout(self.pwd2_h_layout)
        self.all_v_layout.addWidget(self.signin_button)

        self.setLayout(self.all_v_layout)

    def lineedit_init(self):
        self.signin_pwd_line.setEchoMode(QLineEdit.Password)
        self.signin_pwd2_line.setEchoMode(QLineEdit.Password)

        self.signin_user_line.textChanged.connect(self.check_input_func)
        self.signin_pwd_line.textChanged.connect(self.check_input_func)
        self.signin_pwd2_line.textChanged.connect(self.check_input_func)

    def pushbutton_init(self):
        self.signin_button.setEnabled(False)
        self.signin_button.clicked.connect(self.check_signin_func)

    def check_input_func(self):
        if self.signin_user_line.text() and self.signin_pwd_line.text() and self.signin_pwd2_line.text():
            self.signin_button.setEnabled(True)
        else:
            self.signin_button.setEnabled(False)

    def check_signin_func(self):
        if self.signin_pwd_line.text() != self.signin_pwd2_line.text():
            QMessageBox.critical(self, 'Wrong', 'Two Passwords Typed Are Not Same!')
        elif self.signin_user_line.text() not in USER_PWD:
            USER_PWD[self.signin_user_line.text()] = self.signin_pwd_line.text()
            QMessageBox.information(self, 'Information', 'Register Successfully')
            self.close()
        else:
            QMessageBox.critical(self, 'Wrong', 'This Username Has Been Registered!')

        self.signin_user_line.clear()
        self.signin_pwd_line.clear()
        self.signin_pwd2_line.clear()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

5.5 小结

1. setPlaceholderText()方法用于在输入框显示浅灰色的提示文本;

2. exec_()方法可以让窗口成为模态窗口,而调用show()方法,窗口是非模态的。模态窗口将程序控制权占据,只有对当前窗口关闭后才能操作其他窗口;

3. QDialog有exec_()方法,而QWidget没有;

4. 可以用setEchoMode(QLineEdit.Password)将普通输入框中的文字变成原点。

欢迎关注我的微信公众号,发现更多有趣内容:

  • 30
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

la_vie_est_belle

谢谢支持

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

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

打赏作者

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

抵扣说明:

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

余额充值