事件介绍
事件的处理机制非常的复杂,属于PyQt底层的事,不必我们关心,学会使用就行。如果说事件是用来创建窗口,那么信号与槽就是用来对这个控件进行处理。事件属于低级的处理方式,信号与槽是高级的处理方式,一般信号与槽处理不了的问题,再使用事件处理。信号与槽功能强大使用简单但是不能解决所有的问题,事件使用麻烦但是可以处理全部的问题。事件的处理主要是重载类方法,信号与槽的处理主要是绑定、发送以及处理。
事件
-
重写mousePressEvent,keyPressEvent,paintEvent等方法,最常用(控件级)
-
重写QObject.event方法,一般在PyQt没有提供该事件的处理方法时使用(控件级)
-
安装事件过滤器:如果对QObject调用installEventFilter,相当于对这个QObject对象添加了一个过滤器。对于QObject的全部事件来说,都会先经过过滤器的处理,在过滤器里面就可以进行我们自己的处理,比如修改丢弃等,慎用,因为会处理所有的事件,会降低效率(控件级)
-
在QApplication中安装事件过滤器:比QObject的过滤器更强大,对所有的QObject的所有事件进行过滤,且第一时间捕获。事件的过滤先经过QApplication的处理再进过QObject的处理,必须慎用(应用级)
-
重写QApplication的notify方法,要想在任何事件被处理之前捕获事件,唯一的方法就是重写QApplication的notify方法,一般只在调试中使用(应用级)
事件处理流程(紫色部分是应用级处理,绿色部分是对象级处理)
例子
import sys from PyQt5.QtCore import QEvent from PyQt5.QtWidgets import QApplication, QWidget class MyWidget(QWidget): def __init__(self): super(MyWidget, self).__init__() def mousePressEvent(self, mouseEvent): print('MyWidget.mousePressEvent') return QWidget.mousePressEvent(self, mouseEvent) def event(self, event): if event.type() == QEvent.MouseButtonPress: print('MyWidget.event') return QWidget.event(self, event) def eventFilter(self, object, event): if event.type() == QEvent.MouseButtonPress: print('MyWidget.eventFilter') return QWidget.eventFilter(self, object, event) class MyQApplication(QApplication): def __init__(self, param): super(MyQApplication, self).__init__(param) def notify(self, object, event): if event.type() == QEvent.MouseButtonPress: print('MyQApplication.notify') return QApplication.notify(self, object, event) def eventFilter(self, object, event): if event.type() == QEvent.MouseButtonPress: print('MyQApplication.eventFilter') return QApplication.eventFilter(self, object, event) if __name__ == '__main__': app = MyQApplication(sys.argv) app.installEventFilter(app) w = MyWidget() w.installEventFilter(w) w.resize(500, 300) w.move(300, 300) w.setWindowTitle('Simple') w.show() sys.exit(app.exec_())
信号与槽
信号与槽是PyQt的核心机制,也是对象与对象之间的通信方法。信号与槽函数的对应方式是多对多,且信号可以连接信号。除了控件默认的信号外,可以自己定义和实现信号。
信号定义:
mySignal = pyqtSignal([param])
连接信号到槽:
mySignal.connect(handlerFunc)
发送信号:
mySignal.emit([param])
断开信号与槽:
mySignal.disconnect(handlerFunc)
例子:自定义信号并实现与槽的链接
import sys from PyQt5.QtCore import pyqtSignal from PyQt5.QtWidgets import QApplication, QWidget, QPushButton class MyWidget(QWidget): mySignal = pyqtSignal() def __init__(self): super(MyWidget, self).__init__() button = QPushButton(self) button.setText('点我') button.clicked.connect(self.buttonClicked) self.mySignal.connect(self.mySignalHandler) def buttonClicked(self): print('button clicked emit and handler') self.mySignal.emit() def mySignalHandler(self): print('my signal emit and handler') if __name__ == '__main__': app = QApplication(sys.argv) w = MyWidget() w.resize(500, 300) w.move(300, 300) w.setWindowTitle('Simple') w.show() sys.exit(app.exec_())
信号与槽高级玩法
信号重载
import sys from PyQt5.QtCore import pyqtSignal from PyQt5.QtWidgets import QApplication, QWidget, QPushButton class MyWidget(QWidget): # 无参数信号 mySignal_no_aram = pyqtSignal() # 带一个整型参数信号 mySignal_int = pyqtSignal(int) # 带一个整型或字符串信号 mySignal_int_or_str = pyqtSignal([int], [str]) # 带两个参数,int和srt 或 str和str mySignal_two_param = pyqtSignal([int, str], [str, str]) def mySignal_no_aram_handler(self): print('mySignal_no_aram_handler') def mySignal_int_handler(self): print('mySignal_int_handler') def mySignal_int_or_str_int_handler(self): print('mySignal_int_or_str_int_handler') def mySignal_int_or_str_str_handler(self): print('mySignal_int_or_str_str_handler') def mySignal_two_param_int_str_handler(self): print('mySignal_two_param_int_str_handler') def mySignal_two_param_str_str_handler(self): print('mySignal_two_param_str_str_handler') def __init__(self): super(MyWidget, self).__init__() button = QPushButton(self) button.setText('点我') button.clicked.connect(self.onClicked) # 绑定信号到槽函数 self.mySignal_no_aram.connect(self.mySignal_no_aram_handler) self.mySignal_int.connect(self.mySignal_int_handler) self.mySignal_int_or_str[int].connect(self.mySignal_int_or_str_int_handler) self.mySignal_int_or_str[str].connect(self.mySignal_int_or_str_str_handler) self.mySignal_two_param[int, str].connect(self.mySignal_two_param_int_str_handler) self.mySignal_two_param[str, str].connect(self.mySignal_two_param_str_str_handler) def onClicked(self): # 发送信号 self.mySignal_no_aram.emit() self.mySignal_int.emit(1) self.mySignal_int_or_str[int].emit(2) self.mySignal_int_or_str[str].emit('abc') self.mySignal_two_param[int, str].emit(3, 'def') self.mySignal_two_param[str, str].emit('abc', 'def') if __name__ == '__main__': app = QApplication(sys.argv) w = MyWidget() w.resize(500, 300) w.move(300, 300) w.setWindowTitle('Simple') w.show() sys.exit(app.exec_())
使用自定义参数
import sys from functools import partial from PyQt5.QtWidgets import QApplication, QWidget, QPushButton class MyWidget(QWidget): def __init__(self): super(MyWidget, self).__init__() button1 = QPushButton(self) button1.setText('button1') button1.move(10, 10) button2 = QPushButton(self) button2.setText('button2') button2.move(10, 50) # button1.clicked.connect(lambda: self.onClicked(button1)) # button2.clicked.connect(lambda: self.onClicked(button2)) # 等价 button1.clicked.connect(partial(self.onClicked, button1)) button2.clicked.connect(partial(self.onClicked, button2)) def onClicked(self, btn): print("%s" % btn.text()) if __name__ == '__main__': app = QApplication(sys.argv) w = MyWidget() w.resize(500, 300) w.move(300, 300) w.setWindowTitle('Simple') w.show() sys.exit(app.exec_())
使用装饰器定义信号与槽
import sys from PyQt5 import QtCore from PyQt5.QtWidgets import QApplication, QWidget, QPushButton class MyWidget(QWidget): def __init__(self): super(MyWidget, self).__init__() button = QPushButton(self) button.setText('点击') # 设置发送者名称 button.setObjectName('button') # 实现绑定 QtCore.QMetaObject.connectSlotsByName(self) # 槽函数命名规则:on_发送者名称_发射信号名称(self, param) @QtCore.pyqtSlot() def on_button_clicked(self): print('you clicked button') if __name__ == '__main__': app = QApplication(sys.argv) w = MyWidget() w.resize(500, 300) w.move(300, 300) w.setWindowTitle('Simple') w.show() sys.exit(app.exec_())