python qt5 数据改变 触发信号_PyQt5系列教程(5):事件与信号处理

上回我们做了一个猜数字的小游戏,涉及到了信号与槽的知识,今天我们重点的讲解一下这方面的知识!

---------------------------------------------------------华丽的分割线-------------------------------------------------------

GUI应用程序是事件驱动的。 事件主要由应用程序的用户生成。 但它们也可以通过其他手段产生,例如:网络连接,窗口管理器或定时器。 当我们调用应用程序的exec_()方法时,应用程序进入主循环。 主循环获取事件并将其发送到对象。

在事件模型中,有三个参与者:事件来源

事件对象

事件目标

事件源是其状态更改的对象。 它会生成事件。 事件对象(event)将状态更改封装在事件源中。 事件目标是要通知的对象。 事件源对象将处理事件的任务委托给事件目标。

PyQt5具有独特的信号和插槽机制来处理事件。 信号和槽用于对象之间的通信。 发生特定事件时发出信号。 槽可以是任何Python可调用的函数。 当发射连接的信号时会调用一个槽。

---------------------------------------------------------华丽的分割线-------------------------------------------------------

简单的信号与槽示例

代码如下:

#coding=utf-8

import sys

from PyQt5.QtCore import Qt

from PyQt5.QtWidgets import (QWidget, QLCDNumber, QDial, QApplication)

class Example(QWidget):

def __init__(self):

super().__init__()

self.initUi()

def initUi(self):

lcd = QLCDNumber(self)

dial = QDial(self)

self.setGeometry(300, 300, 350, 250)

self.setWindowTitle('学点编程吧')

lcd.setGeometry(100,50,150,60)

dial.setGeometry(120,120,100,100)

dial.valueChanged.connect(lcd.display)

self.show()

if __name__ == '__main__':

app = QApplication(sys.argv)

ex = Example()

sys.exit(app.exec_())

这个例子的执行结果如下:

在这个例子我们展示了一个QtGui.QLCDNumber和一个QtGui.QDial这个两个小部件,当我们拨动QDial这个小部件的时候,LCD屏幕就会显示出此时Dial小部件的值。

dial.valueChanged.connect(lcd.display)

这里我们将QDial这个小部件的一个valueChanged信号连接到lcd数字的显示槽。

QDial对象发送信号。 QLCDNumber接收信号的。 槽是对信号作出反应的方法。

当然你把上面的QDial小部件换成QSlider,也是一样的效果,执行结果如下:

代码请自行参照修改,这里就不再做讲解了。

---------------------------------------------------------华丽的分割线-------------------------------------------------------

重新实现事件处理程序

下面这个例子,我们就重新实现了按下按钮后要如何处理。

#coding=utf-8

import sys

from PyQt5.QtCore import Qt

from PyQt5.QtWidgets import (QWidget, QApplication, QLabel)

class Example(QWidget):

def __init__(self):

super().__init__()

self.initUi()

def initUi(self):

self.setGeometry(300, 300, 350, 250)

self.setWindowTitle('学点编程吧')

self.lab = QLabel('方向',self)

self.lab.setGeometry(150,100,50,50)

self.show()

def keyPressEvent(self, e):

if e.key() == Qt.Key_Up:

self.lab.setText('↑')

elif e.key() == Qt.Key_Down:

self.lab.setText('↓')

elif e.key() == Qt.Key_Left:

self.lab.setText('←')

else:

self.lab.setText('→')

if __name__ == '__main__':

app = QApplication(sys.argv)

ex = Example()

sys.exit(app.exec_())

完成后的效果如下:

def keyPressEvent(self, e):

if e.key() == Qt.Key_Up:

self.lab.setText('↑')

elif e.key() == Qt.Key_Down:

self.lab.setText('↓')

elif e.key() == Qt.Key_Left:

self.lab.setText('←')

else:

self.lab.setText('→')

在我们的例子中,我们重新实现了keyPressEvent()事件处理程序。当我们按住上、下、左、右方向键的时候,窗口中依次会出现对应方位。

关注微信公众号:学点编程吧,发送pyqt55d可以获得全部Qt按键代号。

我们再举一个重写鼠标事件与绘图事件的例子:

#coding=utf-8

import sys

from PyQt5.QtWidgets import (QApplication, QLabel, QWidget)

from PyQt5.QtGui import QPainter, QColor, QPen

from PyQt5.QtCore import Qt

class Example(QWidget):

distance_from_center = 0

def __init__(self):

super().__init__()

self.initUI()

self.setMouseTracking(True)

def initUI(self):

self.setGeometry(200, 200, 1000, 500)

self.setWindowTitle('学点编程吧')

self.label = QLabel(self)

self.label.resize(500, 40)

self.show()

self.pos = None

def mouseMoveEvent(self, event):

distance_from_center = round(((event.y() - 250)**2 + (event.x() - 500)**2)**0.5)

self.label.setText('坐标: ( x:%d,y:%d)' % (event.x(), event.y()) + " 离中心点距离: " + str(distance_from_center))

self.pos = event.pos()

self.update()

def paintEvent(self, event):

if self.pos:

q = QPainter(self)

q.drawLine(0, 0, self.pos.x(), self.pos.y())

if __name__ == '__main__':

app = QApplication(sys.argv)

ex = Example()

sys.exit(app.exec_())

执行的结果如下:

在这个例子中我们实现了鼠标坐标(x,y)的获取,以及绘制一条线,这条线的起点坐标在(0,0),另外一个端点随鼠标移动而移动,同时我们还要计算鼠标坐标与中心点的距离(运用勾股定理进行计算)

self.setMouseTracking(True)

默认情况下禁用鼠标跟踪, 如果启用鼠标跟踪,即使没有按钮被按下,小部件也会接收鼠标移动事件。当然你也可以不写,只需要在执行的过程中按照鼠标左键也行。

def mouseMoveEvent(self, event):

distance_from_center = round(((event.y() - 250)**2 + (event.x() - 500)**2)**0.5)

self.label.setText('坐标: ( x:%d,y:%d)' % (event.x(), event.y()) + " 离中心点距离: " + str(distance_from_center))

self.pos = event.pos()

self.update()

这个函数就是捕捉鼠标移动事件了,我们把得到的坐标已经一些相关的信息显示在label上。必须调用函数update()才能更新图形。

def paintEvent(self, event):

if self.pos:

q = QPainter(self)

q.drawLine(0, 0, self.pos.x(), self.pos.y())

绘图的话需要重写绘图事件,我们生成QPainter对象,然后调用drawLine()方法绘制一条线,需要四个参数,起点的坐标,终点的坐标。后面会详细的对绘图进行举例,这里只是为了配合鼠标移动事件,做一个例子。

---------------------------------------------------------华丽的分割线-------------------------------------------------------

事件发送者

有时,知道哪个窗口小部件是信号的发送者非常有用。 为此,PyQt5具有sender()方法。例如下面这个例子,我们实现了简单的石头、剪刀、布的小游戏。

#coding=utf-8

import sys

from PyQt5.QtWidgets import (QApplication, QMessageBox, QWidget, QPushButton)

from random import randint

class Example(QWidget):

def __init__(self):

super().__init__()

self.initUI()

def initUI(self):

self.setGeometry(200, 200, 300, 300)

self.setWindowTitle('学点编程吧')

bt1 = QPushButton('剪刀',self)

bt1.setGeometry(30,180,50,50)

bt2 = QPushButton('石头',self)

bt2.setGeometry(100,180,50,50)

bt3 = QPushButton('布',self)

bt3.setGeometry(170,180,50,50)

bt1.clicked.connect(self.buttonclicked)

bt2.clicked.connect(self.buttonclicked)

bt3.clicked.connect(self.buttonclicked)

self.show()

def buttonclicked(self):

computer = randint(1,3)

player = 0

sender = self.sender()

if sender.text() == '剪刀':

player = 1

elif sender.text() == '石头':

player = 2

else:

player = 3

if player == computer:

QMessageBox.about(self, '结果', '平手')

elif player == 1 and computer == 2:

QMessageBox.about(self, '结果', '电脑:石头,电脑赢了!')

elif player == 2 and computer == 3:

QMessageBox.about(self, '结果', '电脑:布,电脑赢了!')

elif player == 3 and computer == 1:

QMessageBox.about(self,'结果','电脑:剪刀,电脑赢了!')

elif computer == 1 and player == 2:

QMessageBox.about(self,'结果','电脑:剪刀,玩家赢了!')

elif computer == 2 and player == 3:

QMessageBox.about(self,'结果','电脑:石头,玩家赢了!')

elif computer == 3 and player == 1:

QMessageBox.about(self,'结果','电脑:布,玩家赢了!')

if __name__ == '__main__':

app = QApplication(sys.argv)

ex = Example()

sys.exit(app.exec_())

执行的结果如下:

我们在我们的例子中有三个按钮,分别代表石头、剪刀、布。 在buttonClicked()方法中,我们通过调用sender()方法来确定我们点击了哪个按钮。

bt1.clicked.connect(self.buttonclicked)

bt2.clicked.connect(self.buttonclicked)

bt3.clicked.connect(self.buttonclicked)

三个按钮的clicked信号都连接到同一个槽buttonclicked

def buttonclicked(self):

computer = randint(1,3)

player = 0

sender = self.sender()

if sender.text() == '剪刀':

player = 1

elif sender.text() == '石头':

player = 2

else:

player = 3

if player == computer:

QMessageBox.about(self, '结果', '平手')

elif player == 1 and computer == 2:

QMessageBox.about(self, '结果', '电脑:石头,电脑赢了!')

elif player == 2 and computer == 3:

QMessageBox.about(self, '结果', '电脑:布,电脑赢了!')

elif player == 3 and computer == 1:

QMessageBox.about(self,'结果','电脑:剪刀,电脑赢了!')

elif computer == 1 and player == 2:

QMessageBox.about(self,'结果','电脑:剪刀,玩家赢了!')

elif computer == 2 and player == 3:

QMessageBox.about(self,'结果','电脑:石头,玩家赢了!')

elif computer == 3 and player == 1:

QMessageBox.about(self,'结果','电脑:布,玩家赢了!')

我们通过调用sender()方法来确定信号源,根据信号源确定玩家究竟选择了石头、剪刀、布中的哪一个。 从而与电脑随机给出的数字进行比较,判断输赢。

---------------------------------------------------------华丽的分割线-------------------------------------------------------

发出自定义信号

从QObject创建的对象可以发出信号。 以下示例显示了我们如何发出自定义信号。

#coding=utf-8

import sys

from PyQt5.QtWidgets import (QApplication, QWidget, QMessageBox)

from PyQt5.QtCore import (pyqtSignal, QObject)

class Signal(QObject):

showmouse = pyqtSignal()

class Example(QWidget):

def __init__(self):

super().__init__()

self.initUI()

def initUI(self):

self.setGeometry(200, 200, 300, 300)

self.setWindowTitle('学点编程吧')

self.s = Signal()

self.s.showmouse.connect(self.about)

self.show()

def about(self):

QMessageBox.about(self,'鼠标','你点鼠标了吧!')

def mousePressEvent(self, e):

self.s.showmouse.emit()

if __name__ == '__main__':

app = QApplication(sys.argv)

ex = Example()

sys.exit(app.exec_())

在这个例子当中,当我们单击鼠标的时候,就会弹出对话框告知我们单击了鼠标。执行结果如下:

我们创建一个名为showmouse的新信号。 该信号在鼠标按压事件期间发出。 该信号连接到QMainWindow的about()的槽。

class Signal(QObject):

showmouse = pyqtSignal()

使用pyqtSignal()作为外部Signal类的类属性创建一个信号。

self.s = Signal()

self.s.showmouse.connect(self.about)

自定义showmouse信号连接到QMainWindow的about()的槽。

def mousePressEvent(self, e):

self.s.showmouse.emit()

当我们用鼠标指针点击窗口时,会发出showmouse信号,调用相应的槽函数。

---------------------------------------------------------华丽的分割线-------------------------------------------------------

最后我们总结一下今天的内容:信号与槽连接

事件处理重写

事件发送者

发出自定义信号

ok,今天就到这里,我们下期再约。

如果你想要本次教程中的相关源码,请关注微信公众号:学点编程吧,发送pyqt55,会自动得到相应的百度网盘下载链接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值