PyQt5默认事件处理

一、引言
基于窗体(Widget)的应用程序都是由事件(event)驱动的,鼠标单击、按下某个按键、重绘某个组件、最小化窗口都会产生相应的事件,应用程序对这些事件作出相应的响应处理以实现程序的功能。

二、应用程序的事件循环
事件主要由操作系统的窗口系统产生的,产生的事件进入一个事件队列,由应用程序的事件循环进行处理。以下是PyQt5应用程序的主程序结构:

app = QApplication(sys.argv)
mainform = QmyWidget()
mainform.show()
sys.exit(app.exec_())

app是创建的应用程序对象,最后执行的app.exec_()开启了应用程序的事件处理循环。应用程序会对事件队列中排队的事件进行处理,还可以对相同事件进行合并处理。例如一个界面组件的重绘事件paintEvent,如果在事件队列中重复出现同一事件,应用程序就会合并处理,所以,事件处理是一种异步处理机制

三、事件类型及默认的事件处理函数
在PyQt5中,事件是一种对象,由抽象类QEvent表示。QEvent还有很多子类表示具体的事件,如QKeyEvent表示按键事件,QMouseEvent表示鼠标事件,QPaintEvent表示窗体绘制事件。

当一个事件发生时,PyQt5会根据事件的具体类型用QEvent相应的子类创建一个事件实例对象,然后传递给产生事件的对象的event()函数进行处理。

QObject类及其子类都可以进行事件的处理,但主要还是窗体类(QWidget及其子类)中用到事件处理。以下是QObject类的event()函数的原型:

event(self, <em>e</em>)

参数e是QEvent类型,QEvent类主要有以下3个接口函数:
(1)accept():表示事件接收者接受此事件,对此事件进行处理,接受的事件不会再传播给上层容器组件。
(2)ignore():表示事件接收者忽略次事件,忽略的事件将传播给上层容器组件。
(3)type():返回事件的类型,是枚举类型QEvent.Type,这个枚举类型由100多个值,表示100多个类型的事件。

枚举类型QEvent.Type的每个值都对应于一个事件类,例如QEvent.KeyPress类型表示的是按键事件,对应的事件类是QKeyEvent。

一个类接收到事件后,首先会触发其event()函数,如果event()函数不做任何处理,就会自动触发默认的事件处理函数。

QWidget类是所有界面组件类的父类,它定义了各种事件的默认处理函数,例如鼠标双击事件的枚举类型是QEvent.MouseButtonDblClick,默认的事件处理函数是mouseDoubleClickEvent(),其函数原型是:

mouseDoubleClickEvent(self, event)

参数event是QMouseEvent类型,这是鼠标类型对应的类。
QWidget定义了很多的默认事件处理函数,都会传递一个event参数,但是event的类型由具体事件类型决定。常用的默认事件处理函数如表所示(表中只列出了函数名称,未列出函数输入参数)

默认函数名称 触发时机 参数event类型
mousePressEvent() 鼠标按键按下时触发 QMouseEvent
mouseReleaseEvent() 鼠标按键释放时触发 QMouseEvent
mouseMoveEvent() 鼠标移动时触发 QMouseEvent
mouseDoubleClickEvent() 鼠标双击时触发 QMouseEvent
keyPressEvent() 键盘按键按下时触发 QKeyEvent
keyReleaseEvent() 键盘按键释放时触发 QKeyEvent
paintEvent() 在界面需要重新绘制时触发 QPaintEvent
closeEvent() 一个窗体关闭时触发 QCloseEvent
showEvent() 一个窗体显示时触发 QShowEvent
hideEvent() 一个窗体隐藏时触发 QHideEvent
resizeEvent() 组件改变大小时触发,如一个窗口改变大小时 QResizeEvent
focusInEvent() 当一个组件获得键盘焦点时触发,如一个QLineEdit组件获得输入焦点 QFocusEvent
focusOutEvent() 当一个组件失去键盘焦点时触发,如一个QLineEdit组件失去输入焦点 QFocusEvent
enterEvent() 当鼠标进入组件的屏幕空间时触发,如鼠标移动到一个QPushButton组件上 QEvent
leaveEvent() 当鼠标离开组件的屏幕空间时触发,如鼠标离开一个QPushButton组件 QEvent
dragEnterEvent() 拖动操作正在进行,鼠标移动到组件上方时触发 QDragEnterEvent
dragLeaveEvent() 拖动操作正在进行,鼠标移出组件上方时触发 QDragLeaveEvent
dragMoveEvent() 拖动操作正在进行,鼠标移动时触发 QDragMoveEvent
dropEvent() 当拖动操作在某个组件上放下时触发 QDropEvent

用户在继承于QWidget或其子类的自定义类中可以重新实现这些默认的事件处理函数,从而实现一些需要的功能。例如,QWidget没有clicked()信号,那么就不能通过信号与槽的方式实现对鼠标单击的处理,但是可以重新实现mouseReleaseEvent()函数对鼠标单击事件进行处理。

下列例子对基于项目模板widgetApp的默认事件处理作说明:
PyQt5默认事件处理_第1张图片

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox
from PyQt5.QtCore import pyqtSlot, Qt, QEvent
from PyQt5.QtGui import QPainter, QPixmap

from ui_Widget import Ui_Widget
class QmyWidgrt(QWidget):
	def __init__(self, parent = None):
		super().__init__(parent)	#调用父类构造函数,创建窗体
		self.ui = Ui_Widget()		#创建UI对象
		self.ui.SetupUi(self)		#构造UI

然后在QmyWidget类中重新实现了以下一些典型事件的默认处理函数。
(1)paintEvent()
在界面需要重新绘制时触发,在此事件函数里可以实现一些自定义的绘制功能。绘制窗体背景图片:

def paintEvent(self, event):
	painter = QPainter(self)
	pic = QPixmap("sea1.jpg")
	painter.drawPixmap(0, 0, self.width(), self.height(), pic)
	super().paintEvent(event)

函数的功能是将一个图片文件sea1.jpg绘制到窗体的整个区域,绘图时使用了窗体的画笔对象painter。图片文件sea1.jpg必须与使用其的脚本文件在同一个目录里。最后一行语句表示再执行父类的paintEvent()事件处理函数,以便父类执行其内建的一些操作。

(2)resizeEvent()
在窗体改变大小时触发,在此事件函数里,根据窗体大小,使一个按钮btnTest总是居于窗体的中央。

def resizeEvent(self, event):
	W = self.width()
	H = self.height()
	Wbtn = self.ui.btnTest.width()
	Hbtn = self.ui.btnTest.height()
	self.ui.btnTest.setGeometry((W-Wbtn)/2, (H-Hbtn)/2, Wbtn, Hbtn)

(3)closeEvent()
在窗体关闭时触发,在此事件函数里可以使用一个对话框询问是否关闭窗体,代码如下:

def closeEvent(self, event):
	dlgTitle = "Question消息框"
	strInfo = "closeEvent事件触发,确定要退出吗?"
	defaultBtn = QMessageBox.NoButton
	result = QMessageBox.question(self, dlgTitle, strInfo, QMessageBox.Yes | QMessageBox.No, defaultBtn)
	if(result == QMessageBox.Yes):
		event.accept()			#窗体可关闭
	else:
		event.ignore()			#窗体不可关闭

使用了对话框QMessageBox询问是否关闭窗体。
PyQt5默认事件处理_第2张图片
closeEvent(event)函数的参数event是QCloseEvent类型,根据对话框的返回结果调用QCloseEvent的accept()函数可以关闭窗体,ignore()函数则不关闭窗体。

(4)mousePressEvent()
在鼠标按键按下时触发,在此事件函数里判断鼠标左键是否按下,如果是左键按下就显示鼠标光标处的屏幕坐标,即:

def mousePressEvent(self, event):
	pt = event.pos()		#鼠标位置,QPoint
	if(event.button() == Qt.LeftButton):	#鼠标左键按下
		self.ui.LabMove.setText("(x, y) = (%d, %d)" %(pt.x(), pt.y()))
		rect = self.ui.LabMove.geometry()
		self.ui.LabMove.setGeometry(pt.x(), pt.y(), rect.width(), rect.height())
	super().mousePressEvent(event)

参数event是QMouseEvent类型,QMouseEvent有以下几个接口函数,表示按下的按键的信息和鼠标坐标信息。

  • button()函数:返回值是枚举类型Qt.MouseButton,表示被按下的是鼠标的哪个按键,有Qt.NoButton、Qt.LeftButton、Qt.RightButton和Qt.MidButton等多种取值。
  • buttons()函数:返回值是枚举类型Qt.MouseButton的取值组合,可用于判断多个按键被按下的情况,例如判断鼠标左键和右键同时按下时的语句是:
if(event.buttons() & Qt.LeftButton) and (event.buttons() & Qt.RightButton):
  • x()函数和y()函数:返回值是int类型;pos()函数,返回值是QPoint类型。这两组函数的返回值都表示鼠标光标在接收此事件的组件(widget)上的相对坐标。
  • localPos()函数:返回值是QPointF类型,表示鼠标光标在接收此事件的组件(widget)或项(item)上的相对坐标。
  • windowPos()函数:返回值是QPointF类型,表示鼠标光标在接收此事件的窗口(window)上的相对坐标。
  • globalX()函数和globalY()函数:返回值是int类型;globalPos()函数,返回值是QPoint类型。这两组函数的返回值都表示鼠标光标的全局坐标,也就是屏幕上的坐标。
  • screenPos()函数:返回值是QPointF类型,表示鼠标光标在接收此事件的屏幕(screen)上的全局坐标。

(5)keyPressEvent()或keyReleaseEvent()
keyPressEvent()在键盘上的按键按下时触发,keyReleaseEvent()在按键释放时触发,为keyPressEvent()编写的代码如下:

def keyPressEvent(self, event):
	rect = self.ui.btnMove.geometry()
	if event.key() in set([Qt.Key_A, Qt.Key_Left]):
		self.ui.btnMove.setGeometry(rect.left() - 20, rect.top(), rect.width(), rect.height())
	elif event.key() in set([Qt.Key_D, Qt.Key_Right]):
		self.ui.btnMove.setGeometry(rect.left() + 20, rect.top(), rect.width(), rect.height())
	elif event.key() in set([Qt.Key_W, Qt.Key_Up]):
		self.ui.btnMove.setGeometry(rect.left, rect.top() - 20, rect.width(), rect.height())
	elif event.key() in set([Qt.Key_S, Qt.Key_Down]):
		self.ui.btnMove.setGeometry(rect.left, rect.top() + 20, rect.width(), rect.height())

keyPressEvent(event)函数的参数event是QKeyEvent类型,它有以下两个主要的接口函数,表示按下的按键的信息。

  • key()函数:返回值类型是int,表示被按下的按键,与枚举类型Qt.Key的取值对应。枚举类型Qt.Key包括键盘上所有按键的枚举值,如Qt.Key_Escape、Qt.Key_Tab、Qt.Key_Delete、Qt.Key_Alt、Qt.Key_F1、Qt.Key_A等(详见Qt帮助文档)。
  • modifiers()函数:返回值是枚举类型Qt.KeyboardModifier的取值组合,表示一些用于组合的按键,如Ctrl、Alt、Shift等按键。例如,判断Ctrl+Q是否被按下的语句如下:
if(event.key() == Qt.Key_Q) and (event.modifiers() & Qt.ControlModifier):

这段程序是期望在按下W、A、S、D或上、下、左、右方向键时,窗体上的按钮btnMove能上下左右移动位置。但是却会发现在使用keyPressEvent()事件函数时,只有W、A、S、D有效,而如果使用的是keyReleaseEvent()函数,则W、A、S、D和上、下、左、右方向键都有效。这说明上、下、左、右方向键按下时不会产生QEvent.KeyPress类型的事件。

你可能感兴趣的:(PyQt,GUI,qt,javascript,开发语言)