devexpress textedit 鼠标按下事件_实战PyQt5:095-Qt中的事件处理机制
Qt中的事件(event)事件(event)由窗口系统或Qt自身产生,用以响应所发生的各类事情。例如:当用户按下键盘或者点击鼠标上的按键时,就是产生一个键盘或者鼠标事件;当某个窗口第一次显示的时候,就会产生一个绘制事件,告知窗口绘制它本身,使窗口可见。事件主要分两种情况:与用户交互时发生,比如按下鼠标(mousePressEvent),敲击键盘(keyPressEvent)等。系统内部自身产生,比
Qt中的事件(event)
事件(event)由窗口系统或Qt自身产生,用以响应所发生的各类事情。例如:当用户按下键盘或者点击鼠标上的按键时,就是产生一个键盘或者鼠标事件;当某个窗口第一次显示的时候,就会产生一个绘制事件,告知窗口绘制它本身,使窗口可见。事件主要分两种情况:
- 与用户交互时发生,比如按下鼠标(mousePressEvent),敲击键盘(keyPressEvent)等。
- 系统内部自身产生,比如计时器事件(timerEvent)等。
QEvent类是所有事件类的基类,事件对象里包含事件参数。在Qt中,事件作为一个对象,继承自QEvent。
任何从QObject类派生的类的对象都可以通过QObject.event()函数来接收事件;事件产生时,Qt会创建一个合适的QEvent对象或其派生类对象,然后通过调用QObject类的event()函数将这个事件对象传递给特定的QObject对象或其派生类对象。
Qt 的主事件循环(QCoreApplication::exec())从事件队列中获取本地窗口系统事件,将它们转化为 QEvents,然后将转换后的事件发送给 QObjects。QObjects 通过调用它们的 QObjec.event() 函数接收事件。该函数可以在子类中重新实现,来处理自定义的事件以及添加额外的事件类型,QWidget.event() 就是一个很好的例子。
Qt中的事件类
Qt中的常见事件类型:
- 键盘事件:处理键盘相关事件,比如按键等;
- 鼠标事件:处理鼠标相关事件,比如鼠标按下,释放,双击等事件;
- 拖放事件:拖放事件处理;
- 定时器事件:处理定时器事件;
- 窗口相关事件:处理窗口绘制,移动,改变尺寸,关闭,右键菜单等事件。
事件分发event()函数
事件的分发函数称为事件处理器(event handler)。event()函数就是用来处理事件的分发。如果想在事件的分发之前进行一些操作,比如监听某个按键的按下,就可以在event()函数里处理:
class MyWidget(QWidget): ...... def event(e): if e.key() == Qt.Key_Tab: print('按下了Tab键') return True #按原来的流程来处理事件的分发 return QWidget.event(self, e)
在上面的代码中,MyWidget是QWidget的子类,它重新实现了event()函数,该函数带有一个QEvent类型的参数。当系统产生QEvent对象时,就会传入这个函数并调用。如果传入的事件被识别并处理,则返回True,表示这个事件已经处理完毕,Qt不会将这个事件再分发出去。否则,就继续将该事件分发出去。
Qt系统处理事件时,使用了一种机制,叫做事件传播机制。意思是在子类(比如说一个按钮QPushButton)中发生的事件,调用了子组件的event()函数之后,还会调用父组件(比如说QAbstractButton)的event()函数。event函数的返回值就用于控制这一传播过程。
Qt中的事件传递过程
事件过滤器
在一些应用场景中,需要拦截某个组件发生的事件,让这个事件不再向其他组件传播,这是可以为这个组件或其父组件安装一个事件过滤器(eventFilter)来实现,在实际使用中。需要调用函数installEventFilter()为组件安装过滤器,才能使用事件过滤器这个机制。安装好事件过滤器之后,该组件和其子组件的事件就会被监听。然后重写其eventFilter函数,实现事件过滤。
QEvent中的成员函数
- ignore(): 接收者忽略当前接收到的事件,但事件可能会传递给接收者的父组件;
- accept(): 接收者期望处理当然事件;
- isAccept(): 判断当前事件是否被处理;
- registerEventType(): 注册并返回一个自定义事件类型;
- spontaneous(): 如果事件由应用程序之外产生,比如一个系统事件,返回True,否则返回False;
- type(): 返回事件的类型。QEvent.Type定义了Qt中有效的事件类型。
处理Qt事件的思路
在处理Qt的事件时,一般按照以下思路进行:
- 重写paintEvent、mousePressEvent等事件处理函数。这是最常见、最简单的方式;
- 重写event函数。 event函数是所有对象的事件入口,在QObject和QWidget中的实现中,默认是把事件传递给特定的事件处理函数;
- 在特定对象上面安装事件过滤器。该过滤器仅过滤该对象接收到的事件;
- 在QCoreApplication::instance()上面安装事件过滤器。该过滤器将过滤所有对象的所有事件;
- 重写QCoreApplication::notify()函数。这是最强大的,和全局事件过滤器一样提供完全控制,并且不受线程的限制。
简单示例代码
示例代码演示了对一些基本事件的处理,完整代码如下:
import sysfrom PyQt5 import QtCore, QtGui, QtWidgetsfrom PyQt5.QtCore import Qt, QEvent, QTimerfrom PyQt5.QtGui import QPainterfrom PyQt5.QtWidgets import (QApplication, QWidget, QMenu, QMessageBox) class DemoEvent(QWidget): def __init__(self, parent=None): super(DemoEvent, self).__init__(parent) # 设置窗口标题 self.setWindowTitle('实战PyQt5: QEvent事件演示') # 设置窗口大小 self.resize(400, 320) #初始化数据 self.doubleClicked = False #鼠标双击 self.key='' #按键值 self.text='' #文本信息 self.message='' #提示消息 #定时器,500毫秒后执行 QTimer.singleShot(500, self.onShowHelpInfo) def onShowHelpInfo(self): self.text = '点击这里触发追踪鼠标位置' #触发重绘事件,即触发paintEvent函数 self.update() #关闭应用时,会触发closeEvent def closeEvent(self, event): if QMessageBox.information(self, '关闭应用', '点击按钮关闭应用'): return True #右键菜单事件 def contextMenuEvent(self, event): #实例化一个菜单 menu = QMenu(self) actionTest1 = menu.addAction('测试1') actionTest1.triggered.connect(self.onMenuTest1) actionTest2 = menu.addAction('测试2') actionTest2.triggered.connect(self.onMenuTest2) if not self.message: menu.addSeparator() actionTest3 = menu.addAction('测试3') actionTest3.triggered.connect(self.onMenuTest3) #在鼠标出现的位置显示菜单栏 menu.exec(event.globalPos()) def onMenuTest1(self): self.message = '菜单选项1' self.update() def onMenuTest2(self): self.message = '菜单选项2' self.update() def onMenuTest3(self): self.message = '菜单选项3' self.update() #重绘窗口事件 def paintEvent(self, event): text = self.text pos = text.find('') if pos >= 0: text = text[0:pos] #如果触发了键盘按键,则在文本信息中记录相应的按键信息 if self.key: text += '按下了: {0}'.format(self.key) painter = QPainter(self) painter.setRenderHint(QPainter.TextAntialiasing) #居中绘制文本信息 painter.drawText(self.rect(), Qt.AlignCenter, text) #如果有消息文本,则在底部居中绘制消息文本,3秒钟口消息文本清空重绘 if self.message: #显示消息文本 painter.drawText(self.rect(), Qt.AlignBottom|Qt.AlignLeft, self.message) #3秒后触发清空信息的函数,并重绘事件 QTimer.singleShot(3000, self.clearMessage) def clearMessage(self): self.message = '' self.update() #鼠标释放事件 def mouseReleaseEvent(self, event): #如果是双击释放,就不跟踪鼠标移动 if self.doubleClicked: self.doubleClicked = False else: self.setMouseTracking(not self.hasMouseTracking()) if self.hasMouseTracking(): self.text = '开启鼠标位置跟踪功能.' + '请移动一下鼠标!!!' + '单击鼠标可以关闭这个功能' else: self.text = '闭鼠标跟踪功能.' + '单击鼠标可以开启这个功能' self.update() #鼠标移动事件 def mouseMoveEvent(self, event): if not self.doubleClicked: #窗口坐标转换为屏幕坐标 globalPos = self.mapToGlobal(event.pos()) self.text = '鼠标位置: 窗口坐标为:QPoint({0}, {1}) 屏幕坐标为:QPoint({2}, {3})' .format(event.pos().x(), event.pos().y(), globalPos.x(), globalPos.y()) self.update() #鼠标双击事件 def mouseDoubleClickEvent(self, event): self.doubleClicked = True self.text = '你双击了鼠标' self.update() #键盘按键事件 def keyPressEvent(self, event): self.key = '' if event.key() == Qt.Key_Home: self.key = 'Home' elif event.key() == Qt.Key_End: self.key = 'End' elif event.key() == Qt.Key_PageUp: if event.modifiers() & Qt.ControlModifier: self.key = "Ctrl+PageUp" else: self.key = "PageUp" elif event.key() == Qt.Key_PageDown: if event.modifiers() & Qt.ControlModifier: self.key = "Ctrl+PageDown" else: self.key = "PageDown" elif Qt.Key_A <= event.key() <= Qt.Key_Z: if event.modifiers() & Qt.ShiftModifier: self.key = "Shift+" self.key += event.text() #如果key有字符,不为空,则绘制字符 if self.key: self.update() #否则就继续监视这个事件 else: QWidget.keyPressEvent(self, event) ''' 重新实现其他事件,适用于PyQt没有提供该事件的处理函数的情况, Tab键由于涉及焦点切换,不会传递给keyPressEvent, 因此,需要在这里重新定义。 ''' def event(self, event): #如果有按键按下,并且按键是tab键 if (event.type() == QEvent.KeyPress and event.key() == Qt.Key_Tab): self.key = "在event()中捕获Tab键" self.update() return True return QWidget.event(self, event) if __name__ == '__main__': app = QApplication(sys.argv) window = DemoEvent() window.show() sys.exit(app.exec())
运行效果如下图:
QEvent事件演示
本文知识点
- Qt的事件传播和处理机制;
- Qt中的各种事件;
- 事件发生时,会生成一个QEvent对象,需要even函数进行分发,来调用相应的事件处理器;
- Qt事件可能在处理后传递给父组件对象;
- 事件过滤器(evenFilter)可以令事件进行拦截,阻止其传播,从而实现某些功能。
喜欢本文内容就关注, 收藏,点赞,评论和转发。
更多推荐


所有评论(0)