pyqt 事件监听_PyQt5(3) :实现登录 事件监听处理 程序逻辑功能和界面分离

最终界面如下:

然后是代码:

import sys

from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QMessageBox, QLineEdit, QLabel

class Example(QWidget):

def __init__(self):

super().__init__()

self.initUI()

def initUI(self):

self.setGeometry(300, 300, 400, 300)

self.bt1 = QPushButton('登录', self)

self.bt1.setGeometry(115, 150, 70 ,30)

self.bt1.clicked.connect(self.showMessage) # 相当于就是建立了一个click的处理事件

self.usr = QLabel("用户:", self) # 这里的好像都需要把self作为第二个参数传进去才能显示出来

self.usr.setGeometry(50, 50, 30, 30)

self.pwd = QLabel("密码:", self)

self.pwd.setGeometry(50, 80, 30, 30)

self.text1 = QLineEdit(self)#没有self的话连框都出不来

self.text1.selectAll()

self.text1.setFocus()

self.text1.setGeometry(80, 50, 150 ,30)

self.text2 = QLineEdit( self)

self.text2.selectAll()

self.text2.setFocus()

self.text2.setGeometry(80, 80, 150 ,30)

self.text2.setEchoMode(QLineEdit.Password)

self.show()

def showMessage(self):

acount = self.text1.text() #这里text应该不需要转为字符串吧,返回的应该就是一个字符串。

password= self.text2.text()

print(acount)

print(password)

if len(password) == 0:

QMessageBox.warning(self, "警告", "密码为空")

else:

QMessageBox.warning(self, "警告", "密码长度低于6位")

if acount == "jackhe" and password == "123456" :

QMessageBox.about(self, '','登录成功')

else:

QMessageBox.about(self, '','登录失败!')

def closeEvent(self, event):

reply = QMessageBox.question(self, '确认', '确认退出吗', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

if reply == QMessageBox.Yes:

event.accept()

else:

event.ignore()

if __name__ == '__main__':

app = QApplication(sys.argv)

ex = Example()

sys.exit(app.exec_())

先讲我写完之后的第一感受吧:

感觉这个很捞,因为我发现从知乎上复制下来的不知道为啥会有缩进错误,然后干脆自己重写了一遍,或者是回退到上一行,有分号的enter一下就好。对我这个python小白来说,python的缩进真的恶心,压根看不出来哪里缩进不对,各种报indent。。Java的括号多舒服啊! 然后是忽然记起来python的变量不需要声明,直接使用就行,我第一反应就是去找哪里声明的,,尴尬。还有就是它不会自己自动导包,你需要啥包得自己去import,尴尬。还有就是里面的self的使用泛滥得不是你所能想象,调用方法必须来一个self,使用变量可以来个self。

然后回到我们得代码中来,看看怎么写这个登录界面吧。

(下面的构造函数是我从Java里引入的概念,感觉也是这个概念,大家自行理解)

先看第一步:

if __name__ == '__main__':

app = QApplication(sys.argv)

ex = Example()

sys.exit(app.exec_())

这个就不多解释了,前面文章中已经讲过了,中间是创建对象,创建对象就默认调用构造函数,构造函数中就创建UI。然后就进行应用程序的主循环。

然后看主要代码:

def __init__(self):

super().__init__()

self.initUI()

构造函数调用创建UI的方法。

self.setGeometry(300, 300, 400, 300)

self.bt1 = QPushButton('登录', self)

self.bt1.setGeometry(115, 150, 70 ,30)

self.bt1.clicked.connect(self.showMessage) # 相当于就是建立了一个click的处理事件

self.usr = QLabel("用户:", self) # 这里的好像都需要把self作为第二个参数传进去才能显示出来

self.usr.setGeometry(50, 50, 30, 30)

self.pwd = QLabel("密码:", self)

self.pwd.setGeometry(50, 80, 30, 30)

self.text1 = QLineEdit(self)#没有self的话连框都出不来

self.text1.selectAll()

self.text1.setFocus()

self.text1.setGeometry(80, 50, 150 ,30)

self.text2 = QLineEdit( self)

self.text2.selectAll()

self.text2.setFocus()

self.text2.setGeometry(80, 80, 150 ,30)

self.text2.setEchoMode(QLineEdit.Password)

setGeometry(x,y,width,height) 前两个参数是窗口的x和y位置;第三个是宽度;第四个是窗口的高度。也就是它在一个方法中组合了resize()和move()方法。 这里注意啊!往右是x,往下是y。别搞错了。

self.setGeometry设置的是整个窗体相对显示器的位置。后面的self.usr,pwd ,text1之类的都是相对于窗体的左上角的位置。这个就是确定相对位置的方法,感觉很麻烦。 pyqt5还有另外一种布局方式,可以参考 :学点编程吧:PyQt5系列教程(6):布局 ,和Java的布局差不多吧。

然后这里也是使用了几个组件,感觉很简单,就不讲了,我都是 学点编程吧:PyQt5图形界面编程(目录) 这里一搜,然后一看就用就完事了。

这里注意: 密码框是要在输入的时候不显示出输入的字符, 它本质还是QLineEdit,只是设置了 self.text2.setEchoMode(QLineEdit.Password) 这个属性而已。

然后其它的就没什么了,来到最关键的事件监听和处理上来,也就是:

self.bt1.clicked.connect(self.showMessage)

这段代码,bt1是一个button对象,clickd是这个button对象拥有的一个事件,也就是按一下会产生的影响,connect就是把这个影响传递到showMessage这个方法中。 这个是我最简单的理解方式了,我写过Java界面,安卓界面,前端,所以理解这个比较快。 学点编程吧:PyQt5系列教程(5):事件与信号处理 这里写得就非常系统具体,大家可以学习一波。 我想着值得注意的是 :

keyPressEvent(self, e) 按键时的监听,也就是监听你按下键盘的什么键。

mouseMoveEvent(self, event) 移动鼠标时的监听,比如获取鼠标当前所在所在位置信息

paintEvent(self, event) 重绘方法,这个我暂时理解位Java的重绘,也就是比如窗体的刷新,放大缩小等改变所导致的界面重绘(具体的话后面使用到再细说)

sender()获取事件发送者的信息,从而根据源来判断反应。

s = Signal()

s.showmouse.connect(某个方法) :鼠标点击后运行的方法

感觉还是挺简单的,封装得比Java还好。调用起来贼方便。

然后最后看我们得事件处理方法:

def showMessage(self):

acount = self.text1.text() #这里text应该不需要转为字符串吧,返回的应该就是一个字符串。

password= self.text2.text()

print(acount)

print(password)

if len(password) == 0:

QMessageBox.warning(self, "警告", "密码为空")

else:

QMessageBox.warning(self, "警告", "密码长度低于6位")

if acount == "jackhe" and password == "123456" :

QMessageBox.about(self, '','登录成功')

else:

QMessageBox.about(self, '','登录失败!')

def closeEvent(self, event):

reply = QMessageBox.question(self, '确认', '确认退出吗', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

if reply == QMessageBox.Yes:

event.accept()

else:

event.ignore()

showMessage是点击按钮后的反应:获取输入文本,进行相应的逻辑处理。

closeEvent是重写了方法,代表的是点击最右上角的 x 后的事件,也就是关闭窗口的事件。

不由得感叹这个有点PyQt5有点牛逼啊!

然后接下来,我们QT designer结合eric6再来重做一遍这个功能。

先是新建一个project,然后在选择存储路径的时候,每个项目都单独分出一个文件夹。

ok后进入forms界面:

然后右键空白处,选择new form.

然后选择个基本类型为main windows. 后ok。运行QT designer如下

注意红色标记部分。

然后开始创建我们的登录界面。然后就是把左边的小部件拖拽过来就ok(左键按住拖拽)。如下图,找不到的部件可以直接在左上角的搜索框进行搜索。

然后注意啦,此时我们输入密码是不会隐藏字符的,所以需要把这个edit line的属性echo mode设置为password,如下图(因此后面有类似的都可以用这样的方法进行修改。),此后再输入字符即会变成隐藏字符。

怎么样,是不是感觉这个搞界面简单多了,而且好看多了。关键是不用自己去尝试慢慢修改每个组件的大小和位置了。这个就很舒服。注意,此时在QTdesigner这里一定要点击保存!ctrl+S,以后每次修改界面都要进行保存,然后重新进行后面的编译!

然后这个时候我们回到 eric6 ,点击form界面

然后右键编译 compile all forms

然后进入左边的sources界面:可以发现多了一份py代码,可以进入代码按住F2运行,然后直接点击ok即可

运行效果如下:

也就是说,到这里为止,我们已经把界面做完了,但是里面的逻辑功能啥的都没有。所以,接下来我们要编写逻辑部分代码。

此时我们回到eric6中,进入form界面,右键ui文件,选择 generate dialog code, 然后new,选择类名和文件名。

OK之后,然后把下面的click加上。

然后ok。然后进入source界面:你会发现你多了一个action.py文件,如下图:

这个文件是导入了你刚才的界面模块,然后我们在这里写我们的逻辑代码。刚生成的逻辑代码如下:

from PyQt5.QtCore import pyqtSlot

from PyQt5.QtWidgets import QMainWindow

from .Ui_login import Ui_MainWindow

class Action(QMainWindow, Ui_MainWindow):

"""

Class documentation goes here.

"""

def __init__(self, parent=None):

"""

Constructor

@param parent reference to the parent widget

@type QWidget

"""

super(Action, self).__init__(parent)

self.setupUi(self)

@pyqtSlot()

def on_pushButton_clicked(self):

"""

Slot documentation goes here.

"""

# TODO: not implemented yet

raise NotImplementedError

我们现在要修改这个代码变成我们想要的逻辑功能,我们在这个文件里导入了前面的main windows,所以我们是要在这个文件里运行,所以我们先加上

if __name__ == "__main__":

然后从这里开始。如下图:警告的意思就是我们没导入相应的包。import进来即可。

然后到主逻辑:其实就是把我们之前写的showMessage的东西迁移过来。不过此时要注意名字的改变。

报错1:

原因:导入包不成功 解决方案:删除from后的那一点

报错2:

原因:没有导入sys包 解决方案:import sys

最后在action.py中 F2后如下:

完整代码如下: 先是UI_login.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'D:\Users\DELL\eric6workdirectory\qt3login\login.ui'

#

# Created by: PyQt5 UI code generator 5.6

#

# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):

def setupUi(self, MainWindow):

MainWindow.setObjectName("MainWindow")

MainWindow.resize(800, 600)

self.centralWidget = QtWidgets.QWidget(MainWindow)

self.centralWidget.setObjectName("centralWidget")

self.lineEdit = QtWidgets.QLineEdit(self.centralWidget)

self.lineEdit.setGeometry(QtCore.QRect(260, 160, 113, 20))

self.lineEdit.setObjectName("lineEdit")

self.lineEdit_2 = QtWidgets.QLineEdit(self.centralWidget)

self.lineEdit_2.setGeometry(QtCore.QRect(260, 190, 113, 20))

self.lineEdit_2.setEchoMode(QtWidgets.QLineEdit.Password)

self.lineEdit_2.setObjectName("lineEdit_2")

self.label = QtWidgets.QLabel(self.centralWidget)

self.label.setGeometry(QtCore.QRect(230, 160, 31, 21))

self.label.setObjectName("label")

self.label_2 = QtWidgets.QLabel(self.centralWidget)

self.label_2.setGeometry(QtCore.QRect(230, 190, 54, 21))

self.label_2.setObjectName("label_2")

self.pushButton = QtWidgets.QPushButton(self.centralWidget)

self.pushButton.setGeometry(QtCore.QRect(260, 230, 75, 23))

self.pushButton.setObjectName("pushButton")

MainWindow.setCentralWidget(self.centralWidget)

self.retranslateUi(MainWindow)

QtCore.QMetaObject.connectSlotsByName(MainWindow)

def retranslateUi(self, MainWindow):

_translate = QtCore.QCoreApplication.translate

MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

self.label.setText(_translate("MainWindow", "账号"))

self.label_2.setText(_translate("MainWindow", "密码"))

self.pushButton.setText(_translate("MainWindow", "登录"))

if __name__ == "__main__":

import sys

app = QtWidgets.QApplication(sys.argv)

MainWindow = QtWidgets.QMainWindow()

ui = Ui_MainWindow()

ui.setupUi(MainWindow)

MainWindow.show()

sys.exit(app.exec_())

然后是action.py:

# -*- coding: utf-8 -*-

"""

Module implementing Action.

"""

import sys

from PyQt5.QtCore import pyqtSlot

from PyQt5.QtWidgets import *

from Ui_login import Ui_MainWindow

class Action(QMainWindow, Ui_MainWindow):

def __init__(self, parent=None):

super(Action, self).__init__(parent)

self.setupUi(self)

self.show()

@pyqtSlot()

def on_pushButton_clicked(self):

acount = self.lineEdit.text() #这里text应该不需要转为字符串吧,返回的应该就是一个字符串。

password= self.lineEdit_2.text()

print(acount)

print(password)

if len(password) == 0:

QMessageBox.warning(self, "警告", "密码为空")

else:

QMessageBox.warning(self, "警告", "密码长度低于6位")

if acount == "jackhe" and password == "123456" :

QMessageBox.about(self, '','登录成功')

else:

QMessageBox.about(self, '','登录失败!')

def closeEvent(self, event):

reply = QMessageBox.question(self, '确认', '确认退出吗', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

if reply == QMessageBox.Yes:

event.accept()

else:

event.ignore()

if __name__ == "__main__":

app = QApplication(sys.argv)

action = Action()

sys.exit(app.exec_())

这里的closeEven是我另外加的,按理说应该可以在创建action.py哪里进行选择的。这里忘记了。所以直接自己重写了一个。

这样,我们就实现了界面和逻辑处理的分离。 虽然看起来代码挺多的,但是我们实际写的代码只是逻辑处理部分。

然后我们来分析一下这个自动生成的代码:

首先是UI_login.py:

因为我们运行的是action.py,所以这里的main部分就不用看了。

首先是setupUI,这里就是把整个界面搭建起来,retranslateUi就是把lable和button的文字输入进去。这里是一个界面和文字的分离。

然后看我们重点的action.py。

class Action(QMainWindow, Ui_MainWindow): 这里也就是说它继承了前面的UI_mainwindow这个类,所以这里也就是说这个action类拥有了父类的界面,然后self.show就直接显示出来了。 也就是说,这个实际上是把界面设计放在父类当中,然后把逻辑处理放在子类当中。 然后子类拥有父类的各种属性,比如edit line,label之类的,可以自由操作这些东西。然后运行起来就ok了。

嗯,感觉差不多就是这样了。不得不说这个设计得还是很精妙的。

没错,今天就先到这里了。

这里有很多思想都是我从Java这边借鉴过来的,不一定对,所以欢迎交流讨论。

你可能感兴趣的:(pyqt,事件监听)