PyQt5的事件机制
Posted 哦...
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PyQt5的事件机制相关的知识,希望对你有一定的参考价值。
基于widget的应用程序都是由事件event驱动的,像鼠标单击、按下某个按键、重回组件、最小化窗口等都会产生相应的事件。
应用程序的事件循环
app = QApplication(sys.argv)
form = QWidget()
form.show()
sys.exit(app.exec_())
最后执行的app.exec_()开启了应用程序的事件处理循环。
应用程序会对事件队列中排队的事件进行处理,还可以对相同事件进行合并处理。
事件类型与默认的事件处理函数
PyQt5中,事件是一种对象,事件的基类是抽象类QEvent。
QEvent有众多子类表示具体的事件,例如QKeyEvent表示按键事件,QMouseEvent表示鼠标事件,QPaintEvent表示窗体绘制事件。
当一个事件发生时,PyQt5会根据事件的具体类型用QEvent相应的子类创建一个事件对象,然后传递给产生事件的对象的event()函数进行处理。
event(self,e)
event函数的参数e就是PyQt5调用event函数时传入的事件对象。
QEvent类定义了三个接口函数:
accept() 表示事件接收者接受此事件。被接受的事件不会再继续向上传播给上层容器组件。
ignore() 表示事件接收者忽略此事件。被忽略的事件会继续向上传播给上层容器组件。
type() 返回事件的类型。事件类型是枚举,每一个枚举值都对应一个PyQt5的具体事件类型。例如QMouseEvent的type枚举值为5。不同事件类型对应的枚举值可以参考官方文档。
事件会优先发送给触发事件对象的event函数,但是event函数默认是不做额外的具体处理,而是将事件转派给触发事件对象的各种事件的默认处理函数。例如:event函数会将type为QMouseEvent事件会转派给触发事件对象的mouseMoveEvent()函数,会将type为QMouseButtonDblClick事件会转派给触发事件对象的mouseDoubleClickEvent()函数。
每一个QWidget都定义了很多这样的默认事件处理函数,都会接受一个具体的event事件对象。每一个具体的event对象出了实现基础QEvent对象的接口之外,还会提供很多其它的与事件相关的函数。例如QMouseEvent对象还提供了返回鼠标位置的pos()/localPos()等函数。
用户在继承QWidget或者其子类的自定义类型中可以重新实现这些默认的事件处理函数,从而实现一些需要的功能。例如,某些组件没有clicked信号,那么就不能通过信号与槽的方式实现对鼠标单击的处理,但是可以重新实现mousePressEvent()或mouseReleaseEvent()函数对鼠标事件进行处理。
事件与信号的关系
事件与信号是有区别的,但是也有关联。Qt为某个界面组件定义的信号通常是对某个事件的封装。例如QPushButton有clicked信号,就可以看做是对QPushButton的QMouseReleaseEvent事件的封装。通过编写与信号关联的槽函数可以实现当信号发射时做的事情。一个信号可以关联多个槽函数,一个槽函数也可以关联多个信号。
通过创建PyQt5.QtCore.pyqtSignal对象可以实现自定义信号。调用自定义信号的emit函数就可以将信号发射出去,触发与信号关联的槽函数。
class QmyLabel(QLabel):
doubleClicked = pyqtSignal()
def mouseDoubleClickEvent(self,event):
self.doubleClicked.emit()
class QmyWidget(Qwidget):
def __init__(self,parent=None):
super().__init__(parent)
self.resize(300,300)
self.setWindowTitle('自定义信号')
myLab = QmyLabel(self)
myLab.setText('I am Label')
font = myLab.font()
font.setPointSize(14)
font.setBold(True)
myLab.setFont(font)
size = myLab.sizeHint()
myLab.setGeometry(70,60,size.width(),size.height())
myLab.doubleClicked.connect(self.do_doubleClicked)
def do_doubleClicked(self):
print('Label is DoubleClicked!')
def mouseDoubleClickEvent(self,event):
print('Window is DoubleClicked')
if __name__=='__main__':
app = QApplication(sys.argv)
form = QmyWidget()
form.show()
sys.exit(app.exec_())
QmyLabel自定义了一个doubleClicked信号。当QmyLabel上发生了鼠标双击事件时,会将鼠标双击事件委派给QmyLabel的mouseDobleClickEvent函数处理,处理的方式就是发射自定义信号doubleClicked。
在QmyWidget中,doubleClicked函数的槽函数是QmyWidget的do_doubleClicked函数。该函数一旦检测到doubleClicked信号,槽函数就会执行,在控制台输出Label is DoubleClicked。
事件过滤
通过使用PyQt5的事件过滤器(eventfilter),可以将一个对象上发生的事件委托给另一个对象来检测并处理。
实现事件过滤功能需要完成以下两项操作:
1. 被监测对象使用installEvenFilter()函数将自己注册给监测对象。
2.监测对象实现eventFilter()函数,对监测对象的事件进行处理。
import sys
from PyQt5.QtWidgets import QApplication, QLabel,QWidget,QLabel
from PyQt5.QtCore import Qt,QEvent
class QmyWidget(QWidget):
def __init__(self, parent=None) -> None:
super().__init__(parent)
self.resize(400,400)
self.setWindowTitle('事件委托')
self.laba = QLabel(self)
self.laba.setText('I am Label A')
font = self.laba.font()
font.setPointSize(10)
font.setBold(True)
self.laba.setFont(font)
self.laba.setGeometry(20,20,300,60)
self.laba.installEventFilter(self)
self.labb = QLabel(self)
self.labb.setText('I am Label B')
font = self.labb.font()
font.setPointSize(10)
font.setBold(True)
self.labb.setFont(font)
self.labb.setGeometry(20,100,300,60)
self.labb.installEventFilter(self)
def eventFilter(self, w, e) -> bool:
if w == self.laba:
if e.type()==QEvent.Enter:
self.laba.setText('鼠标来啦')
self.laba.setStyleSheet('background-color:rgb(170,255,255);')
if e.type()==QEvent.Leave:
self.laba.setText('I am Label A')
self.laba.setStyleSheet('')
if w == self.labb:
if e.type()==QEvent.Enter:
self.labb.setText('点我!')
self.labb.setStyleSheet('background-color:rgb(85,255,127);')
if e.type()==QEvent.MouseButtonPress:
self.labb.setText('还真点啊!')
self.labb.setStyleSheet('background-color:rgb(85,255,127);')
if e.type()==QEvent.MouseButtonRelease:
self.labb.setText('点我!')
self.labb.setStyleSheet('background-color:rgb(85,255,127);')
if e.type()==QEvent.Leave:
self.labb.setText('I am Label B')
self.labb.setStyleSheet('')
return super().eventFilter(w, e)
app = QApplication(sys.argv)
form = QmyWidget()
form.show()
sys.exit(app.exec_())
QmyWidget充当窗口,里面有两个QLabel,laba和labb,它们将事件处理全部委托给了QmyWidget。这样,一旦有发生在laba和labb上的事件,QmyWidget的eventFilter函数就会被触发。当然QmyWidget也并不会处理laba和labb的所有事件,所以会通过条件语句判定事件源和事件类型。最后,也是最重要的,因为并不是对laba和labb的事件都做处理,所以一定要使用QWidget的eventFilter函数做善后处理。
以上是关于PyQt5的事件机制的主要内容,如果未能解决你的问题,请参考以下文章
python -- PyQt5(designer)中文详细教程事件和信号