项目实战:《怎么用Python 做一款带用户界面的本地通讯软件》第一节:用户登录,注册。

前言:

从20119年10月份接触Python以来,也有将近有大半年的时间了。在这之前,和编程毫无接触,大学计算机二级都没过…。这大半年的学习主要是通过书籍,视频等方式进行学习,学到的最多的应该是在淘宝买的某培训机构的Python课程。
主要学习了Python的基础语法,和一些网络编程,多任务编程,数据库等的基础知识。也利用了自己所学习到的编程方面的知识,给公司的常用软件做了个外挂程序。深感自身能力的不足,及自学编程者在做编程项目时的无力。所以想通过CSDN平台,用自己所学过的一些东西做点实战项目,一方面梳理自己所学,另一方面也想借此多结交一些想在自学Python路上走的更远一些的朋友。
废话不多说,这次主要想做一个带用户界面的本地通讯软件的练习项目。
即:在window系统下,建立一个可在局域网上使用,提供聊天,文件传输等功能的通讯软件。且该通讯软件需设置提供以上服务的GUI窗口,界面布局可参考PC端微信界面
这篇博客实现的功能为:用户登录,用户注册。

1、效果图

(1):登录及注册

在这里插入图片描述
在这里插入图片描述

(2):记住登录状态

在这里插入图片描述
在这里插入图片描述

2、主要实现功能:

1、客服端登录页面实现功能:

1、检查是否存在已注册用户数据,如无用户数据,提醒注册。
2、用户只有输入用户名和密码时,登录按钮才为可点击状态。
2、登录时检查用户ID及密码,提示错误信息:用户不存在,密码错误。
3、提供记住用户名,用户密码,用户自动登录功能,并可以在三种模式下切换。

2、客户端注册页面实现功能:

1、用户注册,保存注册成功用户数据。
2、检验用户ID,ID只能为字母与数字,不允许中文或其他特殊字符。
3、检查注册用户ID是否已存在,存在时拒绝注册。
4、检查用户密码,用户密码为6-10为字母数字,且首位必须为大写字母。
5、检查两次输入密码是否相同,不相同则提示,拒绝注册。
6、收集用户其他数据,昵称,性别。为可选填对象。
7、如昵称信息未填写,自动分配一个昵称给用户,作为默认昵称。

3、主要技术点

1、Python基础知识:如基础语法,函数,类的继承,重写等。
2、PyQt基础控件的使用,页面布局,单选框,复选框的使用。
3、pyqtSignal 的使用,理解控件焦点事件。
4、PyQt 文本框校验器。

4、代码讲解

1、用户登录按钮设置

# 先设置登录按钮为不可点击状态,当用户输入用户名及密码时才变为可点击状态
        self.login_button.setEnabled(False)

实现方法为: 让用户名及密码单行文本输入框的字符改变信号连接检查用户输入方法,只有当用户名及密码输入框中字符串均不为空时才让登录按钮为可点击状态。代码如下:

    # 单行文本输入框初始化方法
    def line_init(self):
        # 设置提示语
        self.name_line.setPlaceholderText('在此输入用户名')
        self.password_line.setPlaceholderText('在此输入密码')
        # 设置检查单行文本输入框输入状态
        self.name_line.textChanged.connect(self.check_input)
        self.password_line.textChanged.connect(self.check_input)
        
     # 检查文本输入框方法
    def check_input(self):
        # 当用户名及密码输入框均有内容时,设置登录按钮为可点击状态,或者不可点击。
        if self.name_line.text() and self.password_line.text():
            self.login_button.setEnabled(True)
        else:
            self.login_button.setEnabled(False)

2、用户登录方法:

说明:由于这里还没有加上网络网络通讯,也就是还没写客户端,服务端。所以先以文件操作来演示用户登录操作,顺便也可以练习一下Python的官方模块pickle的文件操作。

 		# 登录按钮点击信号绑定槽函数
        self.login_button.clicked.connect(self.do_login)
        
        # 登录方法
        def do_login(self):
        # 获取用户输入的用户名及密码
        name,password = self.name_line.text(),self.password_line.text()
        # 向服务端发送登录请求
        # ----这边先以读取一个本地文件作为试验,模拟登录系统----
        try:
            # 用Python自带模块pickle来进行文件读取操作,以rb方式读取文件
            with open('../data/users.pkl','rb') as f:
                users = pickle.load(f)
        except:
            QMessageBox.warning(self,'警告','暂无用户数据!请先注册!')
            return
        # -----------------模拟登录-----------------------
        if name in users.keys():
            if password == users[name][0]:
                # 检查用户登录状态
                self.check_login_state()
                QMessageBox.information(self,'提示','登录成功!')
            else:
                QMessageBox.warning(self,'警告','密码错误!')
        else:
            QMessageBox.warning(self,'警告','用户不存在!')

3、密码显示

在正常的密码输入框内密码应该是掩码输入的,pyqt中也停供了两种掩码方式:

扫描二维码关注公众号,回复: 11299208 查看本文章
		# 设置用户密码以掩码显示
        # self.password_line.setEchoMode(QLineEdit.Password)
        # 设置用户在输入时明文显示,控件焦点转移后掩码显示
        self.password_line.setEchoMode(QLineEdit.PasswordEchoOnEdit)

解释:第一种(QLineEdit.Password)是用户输入时离开时均为圆圈的小点来显示。
第二种(QLineEdit.PasswordEchoOnEdit)是用户输入时,明文显示,离开时掩码显示。

4、用户登录页面状态

用户登录界面的用户登录状态,模拟大多数网站或软件登录界面,提供了:1、记住用户名,2、记住密码,3、自动登录,三种状态,用的是pyqt里的QCheckBox复选框按钮。

# 设置用户登录界面状态控件,复选框控件
        self.remember_name = QCheckBox('记住用户名')
        self.remember_password = QCheckBox('记住密码')
        self.auto_login = QCheckBox('自动登录')

三个复选框初始化方法:

# 复选框初始化
    def checkbox_init(self):
        # 将三个复选框按钮状态变化信号分别绑定对应槽函数
        self.remember_name.stateChanged.connect(
            self.remember_name_func)
        self.remember_password.stateChanged.connect(
            self.remember_password_func)
        self.auto_login.stateChanged.connect(self.auto_login_func)

分析: 将三个复选框按钮状态变化信号分别绑定对应槽函数。

    # 登录界面,记住用户名方法
    def remember_name_func(self):
        if self.remember_name.isChecked():
            name = self.name_line.text()
            with open('./temp/login.pkl','wb') as f:
                pickle.dump(name,f)
        else:
            with open('./temp/login.pkl','wb') as f:
                pickle.dump(0,f)

    # 登录界面,记住密码方法
    def remember_password_func(self):
        if self.remember_password.isChecked():
            # 用户点击记住密码,用户名也必须记住,
            # 所以记住用户名按钮也需被选中。
            self.remember_name.setChecked(True)
            # 登录界面信息。
            data = [self.name_line.text(),self.password_line.text()]
            with open('./temp/login.pkl','wb') as f:
                pickle.dump(data,f)

    # 登录界面,自动登录方法、
    def auto_login_func(self):
        if self.auto_login.isChecked():
            data = [self.name_line.text(), self.password_line.text()]
            with open('./temp/auto.pkl','wb') as f:
                pickle.dump(data,f)

分析:
1、这里通过当复选框按钮被选中时或未选中时,分别保存对应的文件数据。
2、其中记住用户名复选按钮被选中时,保存字符串文件 login.pkl,未选中时保存整型数据文件 login.pkl。
3、记住密码复选按钮被选中时,保存列表数据文件 login.pkl。
4、自动登录保存列表文件 auto.pkl。

在创建登录页面类的初始化方法中调用读取保存文件方法,来实现记住状态的功能。代码如下:

# 登录页面信息初始化方法
    def login_init(self):
        # 尝试读取记住用户名,或记住用户密码保存文件数据
        try:
            with open('./temp/login.pkl','rb') as f:
                data = pickle.load(f)
            # 判断数据类型,
            # 如果是字符串,及仅选中了记住用户名复选框
            if isinstance(data,str):
                self.name_line.setText(data)
                self.remember_name.setChecked(True)
            else:
                self.name_line.setText(data[0])
                self.password_line.setText(data[1])
                self.remember_name.setChecked(True)
                self.remember_password.setChecked(True)
        except:
            pass
        # 尝试读取自动登录保存文件数据
        try:
            with open('./temp/auto.pkl','rb') as f:
                data2 = pickle.load(f)
            self.name_line.setText(data2[0])
            self.password_line.setText(data2[1])
            # 调用登录方法
            self.do_login()
        except:
            pass

5、注册页面文本输入框设置

注册页面的文本输入框要实现的功能比较多,如密码的掩码显示,第一次输入的密码与第二次输入的密码的对比,还有密码的首字母必须为大写等等。

# 单行文本输入框初始化方法
    # 3个单行文本输入框都绑定检查用户输入槽函数
    # 设置用户密码显示方式:正在输入时明文,焦点转移后掩码
    # 注册提示
    # 设置文本校验器
    # 检查密码合法性
    def line_init(self):
        # 单行文本输入框内容变化绑定按钮显示
        self.name_line.textChanged.connect(self.check_input)
        self.password1_line.textChanged.connect(self.check_input)
        self.password2_line.textChanged.connect(self.check_input)
        # 设置密码显示方式
        self.password1_line.setEchoMode(QLineEdit.PasswordEchoOnEdit)
        self.password2_line.setEchoMode(QLineEdit.PasswordEchoOnEdit)
        # 注册提示
        self.name_line.setPlaceholderText('输入用户名,字母数字,不可为中文或特殊字符。')
        self.password1_line.setPlaceholderText('密码为6到10位数字字母,首字母必须为大写。')
        self.password2_line.setPlaceholderText('请再次确认密码!')
        # 设置文本框校验器
        # 姓名文本框校验器设置
        # 1、创建正则表达式限定输入内容
        name_RegExp = QRegExp("[0-9A-Za-z]*")
        # 2、创建文本框校验器
        name_validator = QRegExpValidator(name_RegExp)
        # 3、文本输入框绑定创建的校验器
        self.name_line.setValidator(name_validator)
        # 设置密码文本输入框校验器
        password_val = QRegExpValidator(QRegExp("^[A-Z][0-9A-Za-z]{10}$"))
        self.password1_line.setValidator(password_val)
        # self.password1_line.focusOutEvent()
        self.password2_line.setValidator(password_val)
        # 检查密码输入,验证密码输入位数,两次密码输入是否一致。
        self.password2_line.focus_out.connect(self.check_password)

特别注意:
这里的passwod2_line 使用的为自定义的单行文本输入框。

		# 再次输入密码的单行文本输入款为自定义的文本输入框
        self.password2_line = MyLineEdit()
        
 # 自定义一单行文本输入框,重写焦点转移事件,让焦点转移时发出一个自定义信号。
class MyLineEdit(QLineEdit):
    focus_out = pyqtSignal(str)
    def focusOutEvent(self,QFocusEvent):
        super(MyLineEdit, self).focusOutEvent(QFocusEvent)
        self.focus_out.emit(self.text())

焦点转移:也就是用户当前选择的焦点转移至下一个控件,如下一个文本输入框,下一个按钮时。这里重写了焦点转移事件,让焦点转移时发出一个focus_out自定义信号
然后这个focus_out自定义信号连接了一个槽函数。check_password,来验证输入密码的合法性。

self.password2_line.focus_out.connect(self.check_password)

 # 检查用户输入密码合法性方法
    def check_password(self):
        password_1 = self.password1_line.text()
        password_2 = self.password2_line.text()

        if len(password_1) < 6:
            QMessageBox.warning(self,'警告','密码位数小于6')
            self.password1_line.setText('')
            self.password2_line.setText('')
        else:
            if password_1 == password_2:
                pass
            else:
                QMessageBox.warning(self,'警告','两次密码输入结果不一致!')
                self.password1_line.setText('')
                self.password2_line.setText('')

6用户注册方法

这里也用文件操作来模拟用户注册操作,代码如下:

	# 用户注册方法
    def register_func(self):
        # 先获取注册用户ID,检查用户ID是否存在
        ID = self.name_line.text()
        try:
            with open('../data/users.pkl','rb') as f1:
                users = pickle.load(f1)
        except:
            users = {}

        # 如果用户ID已存在,提示用户ID已被注册
        if ID in users.keys():
            QMessageBox.information(self,'提示','该用户ID已被注册!')
        # 否则收集用户注册信息
        else:
            gender = self.gender_data()
            user_data = [self.password1_line.text(),
                         self.nick_line.text(),
                         gender]
            # 写入用户信息字典
            users[ID] = user_data
            with open('../data/users.pkl','wb') as f2:
                pickle.dump(users,f2)
            # 提醒用户注册成功,询问是否登录
            choice = QMessageBox.information(self,'提示','注册成功,是否登录?',
                                    QMessageBox.Yes | QMessageBox.No)
            # 如选择是,关闭注册页面,并在登录页面用户ID显示注册ID,密码
            if choice == QMessageBox.Yes:
                self.successful_signal.emit([self.name_line.text(),
                                             self.password1_line.text()])
                self.close()
            # 如选择否,直接关闭注册页面。
            else:
                self.close()

5 源码

本次代码量较多,也只能把自己觉得是主要逻辑的部分代码讲解一下,主要源码分享出来,供大家交流讨论。

1、登录界面源码

# 用户登录页面
class LoginPage(QWidget):
    '''用户注册,登录窗口'''
    def __init__(self):
        # 继承QWidget类
        super(LoginPage, self).__init__()
        # 设置窗口标题
        self.setWindowTitle('本地通讯-ZZ')
        # 设置窗口图标
        self.setWindowIcon(QIcon('../image/title.png'))
        # 设置窗口大小,固定大小
        self.setFixedSize(400,200)
        # label 控件
        self.label_0 = QLabel('用户登录页面')
        # 设置label控件居中
        self.label_0.setAlignment(Qt.AlignCenter)
        # 设置字体样式
        self.label_0.setFont(QFont('宋体', 12, QFont.Bold))
        self.name_label = QLabel('用户名')
        self.password_label = QLabel('密码')
        # 单行文本输入框控件
        self.name_line = QLineEdit()
        self.password_line = QLineEdit()
        # 单行文本输入框初始化
        self.line_init()
        # 按钮
        self.login_button = QPushButton('登录')
        self.register_button = QPushButton('注册')
        self.exit_button = QPushButton('退出')
        # 设置用户登录界面状态控件,复选框控件
        self.remember_name = QCheckBox('记住用户名')
        self.remember_password = QCheckBox('记住密码')
        self.auto_login = QCheckBox('自动登录')
        # 复选框初始化
        self.checkbox_init()
        # 按钮初始化方法
        self.pushbutton_init()
        # 布局管理器
        self.h1_layout = QHBoxLayout() # 水平布局管理器
        self.h2_layout = QHBoxLayout()
        self.grid_layout = QGridLayout() # 网格布局管理器
        self.v_layout = QVBoxLayout() # 垂直布局管理器
        # 页面布局初始化
        self.layout_init()

    # 页面布局初始化方法
    def layout_init(self):
        # 网格布局管理器
        self.grid_layout.setSpacing(20)
        self.grid_layout.addWidget(self.name_label,0,0,1,1)
        self.grid_layout.addWidget(self.name_line,0,1,1,1)
        self.grid_layout.addWidget(self.password_label,1,0,1,1)
        self.grid_layout.addWidget(self.password_line,1,1,1,1)
        # 水平布局布局管理器 1
        self.h1_layout.addWidget(self.login_button)
        self.h1_layout.addWidget(self.register_button)
        self.h1_layout.addWidget(self.exit_button)
        # 水平布局管理器 2
        self.h2_layout.addStretch(1)
        self.h2_layout.addWidget(self.remember_name)
        self.h2_layout.addWidget(self.remember_password)
        self.h2_layout.addWidget(self.auto_login)
        # 垂直布局管理器
        self.v_layout.addStretch(1)
        self.v_layout.addWidget(self.label_0)
        self.v_layout.addSpacing(10)
        self.v_layout.addLayout(self.grid_layout)
        self.v_layout.addSpacing(10)
        self.v_layout.addLayout(self.h2_layout)
        self.v_layout.addSpacing(10)
        self.v_layout.addLayout(self.h1_layout)
        self.v_layout.addStretch(1)
        # 设置最终布局
        self.setLayout(self.v_layout)
        # 登录页面初始化状态
        self.login_init()

    # 单行文本输入框初始化方法
    def line_init(self):
        # 设置提示语
        self.name_line.setPlaceholderText('在此输入用户名')
        self.password_line.setPlaceholderText('在此输入密码')
        # 设置用户密码以掩码显示
        # self.password_line.setEchoMode(QLineEdit.Password)
        # 设置用户在输入时明文显示,控件焦点转移后掩码显示
        self.password_line.setEchoMode(QLineEdit.PasswordEchoOnEdit)
        # 设置检查单行文本输入框输入状态
        self.name_line.textChanged.connect(self.check_input)
        self.password_line.textChanged.connect(self.check_input)

    # 按钮初始化方法
    def pushbutton_init(self):
        # 先设置登录按钮为不可点击状态,当用户输入用户名及密码时才变为可点击状态
        self.login_button.setEnabled(False)
        # 登录按钮点击信号绑定槽函数
        self.login_button.clicked.connect(self.do_login)
        # 注册按钮点击信号绑定槽函数
        self.register_button.clicked.connect(self.do_register)
        # 退出按钮点击信号绑定槽函数
        self.exit_button.clicked.connect(self.close)

    # 复选框初始化
    def checkbox_init(self):
        # 将三个复选框按钮状态变化信号分别绑定对应槽函数
        self.remember_name.stateChanged.connect(
            self.remember_name_func)
        self.remember_password.stateChanged.connect(
            self.remember_password_func)
        self.auto_login.stateChanged.connect(self.auto_login_func)

    # 检查文本输入框方法
    def check_input(self):
        # 当用户名及密码输入框均有内容时,设置登录按钮为可点击状态,或者不可点击。
        if self.name_line.text() and self.password_line.text():
            self.login_button.setEnabled(True)
        else:
            self.login_button.setEnabled(False)

    # 登录方法
    # 在登录方法中,检查用户设置的登录状态
    def do_login(self):
        # 获取用户输入的用户名及密码
        name,password = self.name_line.text(),self.password_line.text()
        # 向服务端发送登录请求
        # ----这边先以读取一个本地文件作为试验,模拟登录系统----
        try:
            # 用Python自带模块pickle来进行文件读取操作,以rb方式读取文件
            with open('../data/users.pkl','rb') as f:
                users = pickle.load(f)
        except:
            QMessageBox.warning(self,'警告','暂无用户数据!请先注册!')
            return
        # -----------------模拟登录-----------------------
        if name in users.keys():
            if password == users[name][0]:
                # 检查用户登录状态
                self.check_login_state()
                QMessageBox.information(self,'提示','登录成功!')
            else:
                QMessageBox.warning(self,'警告','密码错误!')
        else:
            QMessageBox.warning(self,'警告','用户不存在!')

    # 用户注册方法
    def do_register(self):
        # 向服务端发送注册请求,
        # ----这边也以一个文件读取操作,模拟登录系统----
        register_page = RegisterPage()
        # 注册页面的注册成功信号绑定,在登录页面输入注册成功后的用户ID及密码
        register_page.successful_signal.connect(self.successful_func)
        register_page.exec()

    # 注册成功方法
    def successful_func(self,data):
        print(data)
        # 将注册成功数据写入登录页面
        self.name_line.setText(data[0])
        self.password_line.setText(data[1])

    # 登录界面,记住用户名方法
    def remember_name_func(self):
        if self.remember_name.isChecked():
            name = self.name_line.text()
            with open('./temp/login.pkl','wb') as f:
                pickle.dump(name,f)
        else:
            with open('./temp/login.pkl','wb') as f:
                pickle.dump(0,f)

    # 登录界面,记住密码方法
    def remember_password_func(self):
        if self.remember_password.isChecked():
            # 用户点击记住密码,用户名也必须记住,
            # 所以记住用户名按钮也需被选中。
            self.remember_name.setChecked(True)
            # 登录界面信息。
            data = [self.name_line.text(),self.password_line.text()]
            with open('./temp/login.pkl','wb') as f:
                pickle.dump(data,f)

    # 登录界面,自动登录方法、
    def auto_login_func(self):
        if self.auto_login.isChecked():
            data = [self.name_line.text(), self.password_line.text()]
            with open('./temp/auto.pkl','wb') as f:
                pickle.dump(data,f)

    # 登录页面信息初始化方法
    def login_init(self):
        # 尝试读取记住用户名,或记住用户密码保存文件数据
        try:
            with open('./temp/login.pkl','rb') as f:
                data = pickle.load(f)
            # 判断数据类型,
            # 如果是字符串,及仅选中了记住用户名复选框
            if isinstance(data,str):
                self.name_line.setText(data)
                self.remember_name.setChecked(True)
            else:
                self.name_line.setText(data[0])
                self.password_line.setText(data[1])
                self.remember_name.setChecked(True)
                self.remember_password.setChecked(True)
        except:
            pass
        # 尝试读取自动登录保存文件数据
        try:
            with open('./temp/auto.pkl','rb') as f:
                data2 = pickle.load(f)
            self.name_line.setText(data2[0])
            self.password_line.setText(data2[1])
            # 调用登录方法
            self.do_login()
        except:
            pass

    # 检查用户登录状态方法
    def check_login_state(self):
        self.remember_name_func()
        self.remember_password_func()
        self.auto_login_func()

2 用户注册源码:

 注册对话框
class RegisterPage(QDialog):
    # 自定义注册成功信号,传递列表信息
    successful_signal = pyqtSignal(list)
    def __init__(self):
        super(RegisterPage, self).__init__()
        self.setWindowTitle('用户注册')
        self.setWindowIcon(QIcon('../image/title.png'))
        # 设置窗口显示位置
        self.move(900,400)
        self.setFixedSize(450,250)
        self.label_0 = QLabel('欢迎注册')
        self.label_0.setFont(QFont('宋体', 12, QFont.Bold))
        self.label_0.setAlignment(Qt.AlignCenter)
        self.name_label = QLabel('用户ID:')
        self.password1_label = QLabel('用户密码:')
        self.password2_label = QLabel('重复密码:')
        # 其他用户信息label控件
        self.nick_label = QLabel('昵称:')
        self.gender_label = QLabel('性别:')
        # 单行文本输入框
        self.name_line = QLineEdit()
        self.password1_line = QLineEdit()
        # 再次输入密码的单行文本输入款为自定义的文本输入框
        self.password2_line = MyLineEdit()
        self.nick_line = QLineEdit()
        # 性别单选框
        self.male_button = QRadioButton('男')
        self.female_button = QRadioButton('女')
        # 单行文本输入框初始化
        self.line_init()
        # 用户其他信息控件尺寸调整
        self.modify_widget()
        # 按钮
        self.register_button = QPushButton('注册')
        self.cancel_button = QPushButton('取消')
        # 按钮初始化方法
        self.pushbutton_init()
        # 布局管理器
        self.h1_layout = QHBoxLayout()
        self.h2_layout = QHBoxLayout()
        self.grid_layout = QGridLayout()
        self.v_layout = QVBoxLayout()
        # 页面布局初始化
        self.layout_init()

    # 页面布局初始化方法
    def layout_init(self):
        # 网格布局
        # 设置网格布局中控件间距
        self.grid_layout.setSpacing(20)
        self.grid_layout.addWidget(self.name_label,0,0,1,1)
        self.grid_layout.addWidget(self.name_line,0,1,1,1)
        self.grid_layout.addWidget(self.password1_label,1,0,1,1)
        self.grid_layout.addWidget(self.password1_line,1,1,1,1)
        self.grid_layout.addWidget(self.password2_label,2,0,1,1)
        self.grid_layout.addWidget(self.password2_line,2,1,1,1)
        # 水平布局1
        self.h1_layout.addWidget(self.register_button)
        self.h1_layout.addWidget(self.cancel_button)
        # 水平布局2
        self.h2_layout.addWidget(self.nick_label)
        self.h2_layout.addSpacing(12)
        self.h2_layout.addWidget(self.nick_line)
        self.h2_layout.addSpacing(10)
        self.h2_layout.addWidget(self.gender_label)
        self.h2_layout.addWidget(self.male_button)
        self.h2_layout.addWidget(self.female_button)
        # 垂直布局
        self.v_layout.addStretch(1)
        self.v_layout.addWidget(self.label_0)
        self.v_layout.addSpacing(10)
        self.v_layout.addLayout(self.grid_layout)
        self.v_layout.addSpacing(10)
        self.v_layout.addLayout(self.h2_layout)
        self.v_layout.addSpacing(10)
        self.v_layout.addLayout(self.h1_layout)
        self.v_layout.addStretch(1)
        # 设置最终布局
        self.setLayout(self.v_layout)

    # 控件尺寸调整方法
    def modify_widget(self):
        self.nick_label.setMinimumWidth(60)
        self.nick_line.setMaximumWidth(150)

    # 单行文本输入框初始化方法
    # 3个单行文本输入框都绑定检查用户输入槽函数
    # 设置用户密码显示方式:正在输入时明文,焦点转移后掩码
    # 注册提示
    # 设置文本校验器
    # 检查密码合法性
    def line_init(self):
        # 单行文本输入框内容变化绑定按钮显示
        self.name_line.textChanged.connect(self.check_input)
        self.password1_line.textChanged.connect(self.check_input)
        self.password2_line.textChanged.connect(self.check_input)
        # 设置密码显示方式
        self.password1_line.setEchoMode(QLineEdit.PasswordEchoOnEdit)
        self.password2_line.setEchoMode(QLineEdit.PasswordEchoOnEdit)
        # 注册提示
        self.name_line.setPlaceholderText('输入用户名,字母数字,不可为中文或特殊字符。')
        self.password1_line.setPlaceholderText('密码为6到10位数字字母,首字母必须为大写。')
        self.password2_line.setPlaceholderText('请再次确认密码!')
        # 设置文本框校验器
        # 姓名文本框校验器设置
        # 1、创建正则表达式限定输入内容
        name_RegExp = QRegExp("[0-9A-Za-z]*")
        # 2、创建文本框校验器
        name_validator = QRegExpValidator(name_RegExp)
        # 3、文本输入框绑定创建的校验器
        self.name_line.setValidator(name_validator)
        # 设置密码文本输入框校验器
        password_val = QRegExpValidator(QRegExp("^[A-Z][0-9A-Za-z]{10}$"))
        self.password1_line.setValidator(password_val)
        self.password2_line.setValidator(password_val)
        # 检查密码输入,验证密码输入位数,两次密码输入是否一致。
        self.password2_line.focus_out.connect(self.check_password)

    # 按钮初始化方法
    def pushbutton_init(self):
        # 设置注册按钮为不可点击状态,绑定槽函数
        self.register_button.setEnabled(False)
        self.register_button.clicked.connect(self.register_func)
        # 取消按钮绑定取消注册槽函数
        self.cancel_button.clicked.connect(self.cancel_func)

    # 检查输入方法,只有在三个文本输入框都有文字时,注册按钮才为可点击状态
    def check_input(self):
        if (self.name_line.text() and self.password1_line.text()
                and self.password2_line.text() ):
            self.register_button.setEnabled(True)
        else:
            self.register_button.setEnabled(False)

    # 取消注册方法
    # 如果用户在注册界面输入了数据,提示用户是否确认取消注册,如未输入数据则直接退出。
    def cancel_func(self):
        if (self.name_line.text() or self.password1_line.text()
                or self.password2_line.text() ):
            choice = QMessageBox.information(self,'提示','是否取消注册?',
                                    QMessageBox.Yes | QMessageBox.No)
            if choice == QMessageBox.Yes:
                self.close()
            else:
                return
        else:
            self.close()

    # 检查用户输入密码合法性方法
    def check_password(self):
        password_1 = self.password1_line.text()
        password_2 = self.password2_line.text()

        if len(password_1) < 6:
            QMessageBox.warning(self,'警告','密码位数小于6')
            self.password1_line.setText('')
            self.password2_line.setText('')
        else:
            if password_1 == password_2:
                pass
            else:
                QMessageBox.warning(self,'警告','两次密码输入结果不一致!')
                self.password1_line.setText('')
                self.password2_line.setText('')

    # 用户注册方法
    def register_func(self):
        # 先获取注册用户ID,检查用户ID是否存在
        ID = self.name_line.text()
        try:
            with open('../data/users.pkl','rb') as f1:
                users = pickle.load(f1)
        except:
            users = {}

        # 如果用户ID已存在,提示用户ID已被注册
        if ID in users.keys():
            QMessageBox.information(self,'提示','该用户ID已被注册!')
        # 否则收集用户注册信息
        else:
            gender = self.gender_data()
            user_data = [self.password1_line.text(),
                         self.nick_line.text(),
                         gender]
            # 写入用户信息字典
            users[ID] = user_data
            with open('../data/users.pkl','wb') as f2:
                pickle.dump(users,f2)
            # 提醒用户注册成功,询问是否登录
            choice = QMessageBox.information(self,'提示','注册成功,是否登录?',
                                    QMessageBox.Yes | QMessageBox.No)
            # 如选择是,关闭注册页面,并在登录页面用户ID显示注册ID,密码
            if choice == QMessageBox.Yes:
                self.successful_signal.emit([self.name_line.text(),
                                             self.password1_line.text()])
                self.close()
            # 如选择否,直接关闭注册页面。
            else:
                self.close()


    # 用户性别信息收集,男为1,女为2,未选择为0
    def gender_data(self):
        if self.male_button.isChecked():
            gender = 1
        elif self.female_button.isChecked():
            gender = 2
        else:
            gender = 0
        return gender

6 下篇预告

本文主要完成了本地通讯软件项目的登录、注册页面及业务逻辑。下次更新将会加上网络通讯,初步想采取TCP流式套接字的方式。

7 最后

以上即为实现用Python编写本地通讯软件的登录、注册界面逻辑的主要代码段,由于代码量较多,阅读起来不是特别方便,有些依赖文件资源也无法上传。
然后,本人学习时间也不长,疏漏之处也请大家多多包涵。感兴趣的小伙伴可以私信、留言索要源码,一起交流分享。
原创不易,点个赞,留个言鼓励一下!
以上内容为原创,未经允许,禁止转载!!

猜你喜欢

转载自blog.csdn.net/zhouz92/article/details/106531360
今日推荐