5.1 登录界面布局
5.2 完善单行文本输入框和按钮功能
5.3 完善注册界面布局及功能
5.4 整合登录界面和注册界面
5.5 小结
在这一章中,我们会结合前面所学的知识来完善登录框小程序。
为保证代码敲击畅通,可以先引入该程序用到的模块和控件:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QLabel, QLineEdit, QPushButton, \
QGridLayout, QVBoxLayout, QHBoxLayout, QMessageBox
首先完成登录界面布局,请看下方代码:
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()中就行。把对不同控件的操作分开来放在相应的函数中,这样写不仅可以让代码更加清晰明了,也方便日后维护。
此时程序运行截图如下:
该步骤要完成的结果截图如下:
单行文本输入框中有浅灰色的提示文字,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后,账号框和密码框文本都被清空,恢复原状:
接下来就是要完善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()
但是此时运行程序点击登录界面上的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_())
1. setPlaceholderText()方法用于在输入框显示浅灰色的提示文本;
2. exec_()方法可以让窗口成为模态窗口,而调用show()方法,窗口是非模态的。模态窗口将程序控制权占据,只有对当前窗口关闭后才能操作其他窗口;
3. QDialog有exec_()方法,而QWidget没有;
4. 可以用setEchoMode(QLineEdit.Password)将普通输入框中的文字变成原点。
----------------------------------------------------------------------
喜欢的小伙伴可以加入这个Python QQ交流群一起学习:820934083