前面10篇介绍了PyQt5的基本控件,从本篇开始深入介绍PyQt5中的一些常用的方法。包括事件处理、对话框、多窗口应用等。
本篇介绍基于窗体的事件处理。窗体的应用程序都是由事件驱动,按钮的点击、鼠标的点击、重绘窗口。有时候我们在处理一些事件,但不想使用默认的事件处理函数,我们自定义处理函数。
应用程序的事件循环
事件主要由操作系统的窗口系统产生,系统产生的事件会进入一个事件队列,由应用程序的事件循环进行处理。在每个主程序的最下面会有一段代码。
app = QApplication(sys.argv)form = MainWindow()form.show()sys.exit(app.exec_())
app是创建的应用程序,最后执行的app.exec()开启了应用程序的事件处理程序。
默认的事件处理函数
在PyQt5中,QEvent类专门用来处理事件。其下有很多子类例如:QKeyEvent、QmouseEvent等。当一个事件触发之后QEvent的子类会实例化一个事件,然后传给产生事件的对象的event()函数处理。
QWidget类是所有界面组件的父类,定义了各种事件的默认处理函数,例如鼠标双击函数QEvent.MouseButtonDblClick,默认的事件处理函数是mouseDoubleClickEvent。每个事件处理函数都会传递一个event参数。常用的默认事件处理函数如下:
- mousePressEvent():鼠标按键按下
- mouseReleaseEvent():鼠标按钮释放
- mouseMoveEvent():鼠标移动
- mouseDoubleClickEven():鼠标双击
- closeEvent():窗口关闭
新建一个窗口
桌面内所有的控件都是label。
![83f39ad54d6cd0049275d78d906c80b7.png](https://img-blog.csdnimg.cn/img_convert/83f39ad54d6cd0049275d78d906c80b7.png)
UI
重写一些事件处理函数
- paintEvent()
paintEvent()在界面需要绘制时候触发。
def paintEvent(self, event): filePath = self.currentPath + "Image2.jpg" painter = QPainter(self) pic = QPixmap(filePath) painter.drawPixmap(0, 0, self.width(), self.height(), pic) super().paintEvent(event)
- resizeEvent()
resizeEvent()在窗口改变大小时候触发。label标签会在窗口大小改变时候一直显示在窗口的正中间。
def resizeEvent(self, event): W = self.width() H = self.height() labelWidth = self.label.width() labelHeight = self.label.height() self.label.setGeometry((W - labelWidth) / 2, (H - labelHeight) / 2, labelWidth, labelHeight)
![dd059f75139d8e70202bc588167a803d.gif](https://img-blog.csdnimg.cn/img_convert/dd059f75139d8e70202bc588167a803d.gif)
resizeEvent
- closeEvent()
closeEvent()窗口关闭时触发,需要关闭窗口时会弹出一个对话框,是否关闭窗口。如果点击Yes则接受accept这个事件,否则忽略ignore。QMessageBox具体使用后面会介绍。
def closeEvent(self, event): strTitle = "消息提示框!!!" strInfo = "closeEvent事件,确定要退出吗?" btnDia = QMessageBox.NoButton result = QMessageBox.question(self, strTitle, strInfo, QMessageBox.Yes | QMessageBox.No, btnDia) if result == QMessageBox.Yes: event.accept() else: event.ignore()
![018375457025c8c01cc2b10de0c83b93.gif](https://img-blog.csdnimg.cn/img_convert/018375457025c8c01cc2b10de0c83b93.gif)
关闭窗口
- mousePressEvent()
mousePressEvent()鼠标点击时候触发。QWidget没有没有clicked信号,所以就不能通过信号和槽处理鼠标的单击,我们可以通过重写mousePressEvent()函数。在鼠标光标处显示当前光标所处的坐标。
![7365f104317d38face0a8f1d506131a0.png](https://img-blog.csdnimg.cn/img_convert/7365f104317d38face0a8f1d506131a0.png)
Signal/slot
- event.pos():获取当的位置。
- Qt.LeftButton:返回一个枚举类型Qt.MouseButton,鼠标的哪一个按钮被按下。
- x()和y(),获取当前位置的下x,y坐标。
def mousePressEvent(self, event): mousePosition = event.pos() if event.button() == Qt.LeftButton: x = mousePosition.x() y = mousePosition.y() self.label_2.setText("(x,y)=(%d,%d)" % (x, y)) rect = self.label_2.geometry() self.label_2.setGeometry(x, y, rect.width(), rect.height()) super().mousePressEvent(event)
![a51fb0f9c39b1af5584574e587abd9a7.gif](https://img-blog.csdnimg.cn/img_convert/a51fb0f9c39b1af5584574e587abd9a7.gif)
鼠标坐标
- keyPressEvent()
keyPressEvent()键盘按钮被按下时候触发。当按下键盘的按键时候,会在label_3中显示一个导弹。当按下W、A、S、D按键时候将标签移动,就像游戏中的前进、后退、左移、右移。
- key():返回值是int类型,与枚举类型Qt.Key的值对应,枚举类型包括键盘上所有按键的枚举值。
def keyPressEvent(self, event): filePath = self.currentPath + "Image反坦克导弹.png" self.Pixmap.load(filePath) width = self.label_3.width() height = self.label_3.height() pix = self.Pixmap.scaled(width, height) self.label_3.setPixmap(pix) rect = self.label_3.geometry() if event.key() == Qt.Key_W: self.label_3.setGeometry(rect.left(), rect.top()-2, rect.width(), rect.height()) if event.key() == Qt.Key_A: self.label_3.setGeometry(rect.left()-2, rect.top(), rect.width(), rect.height()) if event.key() == Qt.Key_S: self.label_3.setGeometry(rect.left(), rect.top()+2, rect.width(), rect.height()) if event.key() == Qt.Key_D: self.label_3.setGeometry(rect.left()+2, rect.top(), rect.width(), rect.height())
![0867408e77e37f3d5019de97947ff469.gif](https://img-blog.csdnimg.cn/img_convert/0867408e77e37f3d5019de97947ff469.gif)
keyPressEvent
事件与信号的关系
在使用一些页面组件时候,我们通常使用其自带的信号,根据信号编写槽函数。但是有些组件却没有我们需要的信号。比如我们如果想让一个label有一个点击的功能,但是label没有clicked信号,我们只能自建一个具有clicked信号功能的标签类。
![5e4c3d641b17f1353a125ab085a12ae2.png](https://img-blog.csdnimg.cn/img_convert/5e4c3d641b17f1353a125ab085a12ae2.png)
label的信号
class newQLabel(QLabel): doubleClicked = pyqtSignal() def mouseDoubleClickEvent(self, event): self.doubleClicked.emit()
自定义一个信号:doubleClicked = pyqtSignal()
自定义一个双击处理函数:def mouseDoubleClickEvent(self, event),当双击时候发射信号。
- 使用自定义标签类新一个标签newLabel。
self.newLabel = newQLabel(self)self.newLabel.setText("快双击我啊!!!")font = self.newLabel.font()font.setPointSize(18)font.setBold(True)size = self.newLabel.sizeHint()self.newLabel.setGeometry(100, 500, size.width(), size.height())
- 双击槽函数
self.newLabel.doubleClicked.connect(self.label_doubleClicked)
def label_doubleClicked(self): self.count += 1 self.newLabel.setText("你双击了Label%d次" % self.count)
![8fff94b2cbe5f5506bd5c3cda6f68e1d.gif](https://img-blog.csdnimg.cn/img_convert/8fff94b2cbe5f5506bd5c3cda6f68e1d.gif)
双击Label
信号的过滤及拦截
一个组件产生事件首先发送给event()函数,如果没有重写event函数,则会调用默认的事件处理函数,我们可以通过重写event()函数对一些事件做过滤或者屏蔽。最后要调用父类的event函数。不然别的event函数都没办法使用。
def event(self, event): if event.type() == QEvent.Paint: self.label.setText("事件函数已被修改,无法显示背景图片") return True return super(MainWindow, self).event(event)
![f749c44fdf1d30b28032c6f42d9dfba5.png](https://img-blog.csdnimg.cn/img_convert/f749c44fdf1d30b28032c6f42d9dfba5.png)
把paintEvent屏蔽
- 事件过滤器
事件过滤器可以将一个对象的事件委托给另一个对象来检查并处理。
- 被监测的对象使用installEventFilter()将自己注册给监测对象。
- 监测对象使用eventFilter()函数,对监测到的对象和事件作出处理。
- 先安装事件过滤器
self.picture.installEventFilter(self)
self是界面的窗体,把界面窗体设置为事件监测者,picture组件上的事件都会交给窗体处理。
def eventFilter(self, watched, event): if watched == self.picture: if event.type() == QEvent.Enter: self.label_4.setText("鼠标光标进入") elif event.type() == QEvent.Leave: self.label_4.setText("鼠标光标移出") elif event.type() == QEvent.MouseButtonPress: self.label_4.setText("鼠标按下") elif event.type() == QEvent.MouseButtonRelease: self.label_4.setText("鼠标释放") return super().eventFilter(watched, event)
一个简单的案例介绍事件的使用。如果需要源代码可关注私聊,感谢支持!!!