信号/槽机制可以说是对事件处理机制的高级封装,如果说事件是用来创建窗口控件的,那么信号与槽就是用来对这个窗口控件进行使用的。
例如,在使用一个按钮时,只需要关注 clicked 信号,不必关注这个按钮如何接收并处理鼠标单击事件,以及发射这个信号。
但是如果要重载一个按钮,就需要关注这个问题。如果要改变它的行为,则在按下鼠标按键时触发 clicked 信号,而不是在释放时触发 clicked 信号。
可视化应用程序在接受外界输入设备的输入时,例如鼠标、键盘等的操作,会对输入设备输入的信息进行分类,根据分类的不同,用不同的函数进行处理,做出不同的反应。
外界对 PySide程序进行输人信息的过程称为事件,例如在窗口上单击鼠标、用鼠标拖动窗口在输人框中输人数据等,这些都是外界对程序的输人,都可以称为事件。
PySide 程序对外界的输人进行处理的过程称为事件处理,根据外界输入信息的不同,处理事件的函数也不同。
前面编制的可视化程序中,在主程序中都会创建一个 QApplication 的应用程序实例对象,然后调用实例对象的 exec()函数,这将使应用程序进入一个循环,不断监听外界输入的信息。当输人的信息满足某种分类时,将会产生一个事件对象 QEvent(),事件对象中记录了外界输人的信息,并将事件对象发送给处理该事件对象的函数进行处理。
事件与前面讲过的信号与槽相似,但是又有不同。信号是指控件或窗口本身满足一定条件时,发送一个带数据的信息或不带数据的信息,需要编程人员为这个信息单独写处理这个信息的槽函数,并将信号和槽函数关联,发送信号时,自动执行与之关联的槽函数。而事件是外界对程序的输人,将外界的输人进行分类后交给函数处理,处理事件的函数是固定的,只需要编程人员把处理事件的函数重写,来达到处理外界输入的目的,而不需要将事件与处理事件的函数进行连接,系统会自动调用能处理事件的函数,并把相关数据作为实参传递给处理事件的函数。
下面是一个处理鼠标单击事件的程序,在窗口的空白处单击鼠标左键,在 QLineEdit 控件上显示出鼠标单击点处的窗口坐标值,单击鼠标右键,显示右键单击处屏幕坐标值。
单击鼠标左键或右键将会产生QMouseEvent 事件,QMouseEvent事件的实例对象中有与鼠标事件相关的属性,如 button()方法获取单击的是左键还是右键,x()和 y()方法取鼠标单击点处窗口坐值,globalX()和 globalY()方法获取鼠标单击点处屏幕坐标值。
QWidget窗口处理 QMouseEvent 事件的函数有:
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/1 20:31
# File_name: 01-简单的鼠标点击事件.py
import PySide6.QtGui
from PySide6.QtWidgets import QApplication,QWidget,QLabel
from PySide6.QtCore import Qt
import sys
class MyWindow(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.resize(500,500)
self.qlabel = QLabel(self)
self.qlabel.setGeometry(15,5,500,30)
self.qlabel.setText("请点击")
def mousePressEvent(self,event: PySide6.QtGui.QMouseEvent)-> None: # 重写处理mousePress 事件的函数
super().mousePressEvent(event)
template1 ="单击点的窗口坐标是x:{} y:{}"
template2 ="单击点的屏幕坐标是x:{} y:{}"
if event.button()== Qt.LeftButton: # button()获取键或右键
string = template1.format(event.position().x(),event.position().y())# x()和()获取窗口坐标
self.qlabel.setText(string)
if event.button()== Qt.RightButton: # globalX()和globalY()获取全局坐标
string = template2.format(event.globalPosition().x(),event.globalPosition().y())
self.qlabel.setText(string)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
win.show()
sys.exit(app.exec())
官方文档
QEvent类是所有事件的基类,它在 QtCore 模块中。
外界输人给序的信息首先交给QEvent 进行分类,得到不同类型的事件,然后系统将事件及相关信息交给控件或窗口的事件处理函数进行处理,得到对外界输人的响应QEvent 类的属性只有 accepted。
Qt的主事件循环(exec())从事件队列中获取本机窗口系统事件,将它们转换为QEvents,并将转换后的事件发送给QObjects。
通常,事件来自底层窗口系统(自发性()返回true),但也可以使用sendEvent()和postEvent()手动发送事件(自发性(()返回false)。
QObjects通过调用其event()函数来接收事件。该函数可以在子类中重新实现,以自定义事件处理并添加额外的事件类型;event()是一个值得注意的例子。默认情况下,事件被调度到timerEvent()和mouseMoveEvent()等事件处理程序。installEventFilter()允许一个对象拦截去往另一个对象的事件。
基本的QEvent只包含一个事件类型参数和一个"accept"标志。accept标志用accept()设置,并用ignore()清除。它是默认设置的,但不要依赖于此,因为子类可能会选择在其构造函数中清除它。
QEvent的子类包含描述特定事件的附加参数。
常用方法如表所示,主要方法介绍如下:
QEvent的方法及参数类型 | 返回值的类型 | 说明 |
---|---|---|
setAccepted(accepted: bool) | None | 设置事件是否被接受 |
accept() | None | 事件被接受 设置事件对象的accept标志,相当于调用setAccepted(true)。 设置accept参数表示事件接收器想要该事件。不需要的事件可能会传播到父窗口小部件。 |
clone() | QEvent | 重写该函数,返回事件的复本 创建并返回此事件的相同副本。 |
ignore() | None | 事件被拒绝 清除事件对象的accept标志参数,相当于调用setAccepted(false)。 清除accept参数表示事件接收器不想要该事件。不需要的事件可能会传播到父窗口小部件。 |
isAccepted() | bool | 事件是否被接受 |
isInputEvent() | bool | 如果事件对象是QInputEvent或其子类之一,则返回true。 |
isPointerEvent() | bool | 如果事件对象是QPointerEvent或其子类之一,则返回true。 |
isSinglePointEvent() | bool | 是 QSinglePointEvent事件时返回True |
spontaneous() | bool | 获取事件是否立即被处理 如果事件源自应用程序外部(系统事件),则返回true;否则返回false。 |
type() | QEvent.Type | 获取事件的类型 |
[static]registerEventType([hint=-1]) | int | 注册新的事件类型 注册并返回自定义事件类型。如果提供的提示可用,将使用它,否则它将返回一个介于User和MaxUser之间的值,该值尚未注册。如果提示的值不在User和MaxUser之间,则会忽略该提示。 如果已获取所有可用值或程序正在关闭,则返回-1。 |
- 用accept()或 setAccepted(True)方法接受一个事件
- 用ignore()或 setAccepted(False)方法拒绝一个事件。
- 被接受的事件不会再传递给其他对象;被拒绝的事件会传递给其他对象处理,如果没有对象处理,则该事件会被丢弃。
- 如果事件被QWidget的event()函数进行了处理则用spontaneous()方法的返回值是True,否则返回值是False。
- event()函数根据事件类型起到分发事件到指定处理函数的作用,可以在event()函数中对事件进行处理
- 用registerEventType(hint:int=-1)方法可以注册一个新事件类型其中hint的取值介于QEventUser(1000)和 QEvent.MaxUser(65535)之间,返回新事件的D号。
用type()方法可以返回事件的类型。QEvent中定义了事件的类型,QEent定义的主要事件类型如表所示:
PySide6.QtCore.QEvent.Type
(继承)此枚举类型定义 Qt 中的有效事件类型。事件类型和每种类型的专用类如下所示:enum.IntEnum
Constant | Description |
---|---|
QEvent.None | 不是一个事件。 |
QEvent.ActionAdded | 激活扩展器已添加新操作()。QActionEvent |
QEvent.ActionChanged | 操作已更改()。QActionEvent |
QEvent.ActionRemoved | 已删除一个操作(QActionEvent)。 |
QEvent.ActivationChange | 小部件的顶级窗口激活状态已更改。 |
QEvent.ApplicationActivate | 此枚举已被弃用。请改用ApplicationStateChange。 |
QEvent.ApplicationActivated | 此枚举已被弃用。请改用ApplicationStateChange。 |
QEvent.ApplicationDeactivate | 此枚举已被弃用。请改用ApplicationStateChange。 |
QEvent.ApplicationFontChange | 默认应用程序字体已更改。 |
QEvent.ApplicationLayoutDirectionChange | 默认的应用程序布局方向已更改。 |
QEvent.ApplicationPaletteChange | 默认的应用程序选项板已更改。 |
QEvent.ApplicationStateChange | 应用程序的状态已更改。 |
QEvent.ApplicationWindowIconChange | 应用程序的图标已更改。 |
QEvent.ChildAdded | 一个对象得到一个子对象(QChildEvent)。 |
QEvent.ChildPolished | 一个小部件的子级被抛光(QChildEvent)。 |
QEvent.ChildRemoved | 一个对象失去了一个子对象(QChildEvent)。 |
QEvent.Clipboard | 剪贴板内容已更改。 |
QEvent.Close | 小部件已关闭(QCloseEvent)。 |
QEvent.CloseSoftwareInputPanel | 一个小部件想要关闭软件输入面板(SIP)。 |
QEvent.ContentsRectChange | 小部件内容矩形的边距发生了变化。 |
QEvent.ContextMenu | 上下文弹出菜单(QContextMenuEvent)。 |
QEvent.CursorChange | 小部件的光标已更改。 |
QEvent.DeferredDelete | 对象在清理后将被删除(QDeferredDeleteEvent) |
QEvent.DragEnter | 光标在拖放操作(QDragEnterEvent)期间进入一个小部件。 |
QEvent.DragLeave | 在拖放操作(QDragLeaveEvent)期间,光标会离开一个小部件。 |
QEvent.DragMove | 正在进行拖放操作(QDragMoveEvent)。 |
QEvent.Drop | 拖放操作已完成(QDropEvent)。 |
QEvent.DynamicPropertyChange | 已向对象添加、更改或删除动态属性。 |
QEvent.EnabledChange | 小工具的启用状态已更改。 |
QEvent.Enter | 鼠标进入小部件的边界(QEnterEvent)。 |
QEvent.EnterEditFocus | 编辑器小部件获得编辑的焦点。必须定义QT_KEYPAD_NAMEVIGATION。 |
QEvent.EnterWhatsThisMode | 当应用程序进入"What’s This?"模式时,发送到顶层窗口小部件。 |
QEvent.Expose | 当窗口的屏幕内容无效并且需要从后台存储中清除时,发送到窗口。 |
QEvent.FileOpen | 文件打开请求(QFileOpenEvent)。 |
QEvent.FocusIn | 小工具或窗口获得键盘焦点(QFocusEvent)。 |
QEvent.FocusOut | 小工具或窗口失去键盘焦点(QFocusEvent)。 |
QEvent.FocusAboutToChange | 小工具或窗口焦点即将更改(QFocusEvent) |
QEvent.FontChange | 小工具的字体已更改。 |
QEvent.Gesture | 触发了一个手势(QEstureEvent)。 |
QEvent.GestureOverride | 触发了手势覆盖(QEstureEvent)。 |
QEvent.GrabKeyboard | 项目获得键盘抓取(仅限QGraphicsItem)。 |
QEvent.GrabMouse | 物品获得鼠标抓取(仅限QGraphicsItem)。 |
QEvent.GraphicsSceneContextMenu | 图形场景上的上下文弹出菜单(QGraphicsSceneContextMenuEvent)。 |
QEvent.GraphicsSceneDragEnter | 光标在拖放操作(QGraphicsSceneDragDropEvent)期间进入图形场景。 |
QEvent.GraphicsSceneDragLeave | 在拖放操作(QGraphicsSceneDragDropEvent)期间,光标会离开图形场景。 |
QEvent.GraphicsSceneDragMove | 正在对场景进行拖放操作(QGraphicsSceneDragDropEvent)。 |
QEvent.GraphicsSceneDrop | 在场景上完成拖放操作(QGraphicsSceneDragDropEvent)。 |
QEvent.GraphicsSceneHelp | 用户请求图形场景的帮助(QHelpEvent)。 |
QEvent.GraphicsSceneHoverEnter | 鼠标光标进入图形场景中的悬停项目(QGraphicsSceneHoverEvent)。 |
QEvent.GraphicsSceneHoverLeave | 鼠标光标会在图形场景中留下悬停项目(QGraphicsSceneHoverEvent)。 |
QEvent.GraphicsSceneHoverMove | 鼠标光标在图形场景中的悬停项目内移动(QGraphicsSceneHoverEvent)。 |
QEvent.GraphicsSceneMouseDoubleClick | 在图形场景(QGraphicsSceneMouseEvent)中再次按下鼠标(双击)。 |
QEvent.GraphicsSceneMouseMove | 在图形场景中移动鼠标(QGraphicsSceneMouseEvent)。 |
QEvent.GraphicsSceneMousePress | 在图形场景中按下鼠标(QGraphicsSceneMouseEvent)。 |
QEvent.GraphicsSceneMouseRelease | 在图形场景中释放鼠标(QGraphicsSceneMouseEvent)。 |
QEvent.GraphicsSceneMove | 小部件已移动(QGraphicsSceneMoveEvent)。 |
QEvent.GraphicsSceneResize | 已调整小部件的大小(QGraphicsSceneResizeEvent)。 |
QEvent.GraphicsSceneWheel | 鼠标滚轮在图形场景中滚动(QGraphicsSceneWheelEvent)。 |
QEvent.GraphicsSceneLeave | 光标将离开图形场景(QGraphicsSceneWheelEvent)。 |
QEvent.Hide | 小工具已隐藏(QHideEvent)。 |
QEvent.HideToParent | 一个子窗口小部件已被隐藏。 |
QEvent.HoverEnter | 鼠标光标进入一个悬停小部件(QOverEvent)。 |
QEvent.HoverLeave | 鼠标光标离开一个悬停小部件(QOverEvent)。 |
QEvent.HoverMove | 鼠标光标在悬停小部件(QOverEvent)内移动。 |
QEvent.IconDrag | 窗口的主图标已被拖走(QIconDragEvent)。 |
QEvent.IconTextChange | 小工具的图标文本已更改。(已弃用) |
QEvent.InputMethod | 正在使用输入方法(QInputMethodEvent)。 |
QEvent.InputMethodQuery | 输入法查询事件(QInputMethodQueryEvent) |
QEvent.KeyboardLayoutChange | 键盘布局已更改。 |
QEvent.KeyPress | 按键按下(QKeyEvent)。 |
QEvent.KeyRelease | 按键释放(QKeyEvent)。 |
QEvent.LanguageChange | 应用程序翻译已更改。 |
QEvent.LayoutDirectionChange | 布局的方向已更改。 |
QEvent.LayoutRequest | 小工具布局需要重做。 |
QEvent.Leave | 鼠标离开小部件的边界。 |
QEvent.LeaveEditFocus | 编辑器小部件在编辑时失去焦点。必须定义QT_KEYPAD_NAMEVIGATION。 |
QEvent.LeaveWhatsThisMode | 当应用程序离开"What’s This?"模式时,发送到顶层小部件。 |
QEvent.LocaleChange | 系统区域设置已更改。 |
QEvent.NonClientAreaMouseButtonDblClick | 在客户端区域外发生鼠标双击(QMouseEvent)。 |
QEvent.NonClientAreaMouseButtonPress | 在客户端区域外发生鼠标按键按下(QMouseEvent)。 |
QEvent.NonClientAreaMouseButtonRelease | 客户端区域外发生鼠标按钮释放(QMouseEvent)。 |
QEvent.NonClientAreaMouseMove | 在客户端区域外发生鼠标移动(QMouseEvent)。 |
QEvent.MacSizeChange | 用户更改了小部件的大小(仅限macOS)。 |
QEvent.MetaCall | 通过invokeMethod()进行的异步方法调用。 |
QEvent.ModifiedChange | 小工具修改状态已更改。 |
QEvent.MouseButtonDblClick | 再次按下鼠标(QMouseEvent)。 |
QEvent.MouseButtonPress | 鼠标按下(QMouseEvent)。 |
QEvent.MouseButtonRelease | 鼠标释放(QMouseEvent)。 |
QEvent.MouseMove | 鼠标移动(QMouseEvent)。 |
QEvent.MouseTrackingChange | 鼠标跟踪状态已更改。 |
QEvent.Move | 小工具的位置已更改(QMoveEvent)。 |
QEvent.NativeGesture | 系统检测到一个手势(QNativeGestureEvent)。 |
QEvent.OrientationChange | 屏幕方向发生变化(QScreenOrientationChangeEvent)。 |
QEvent.Paint | 需要屏幕更新(QPaintEvent)。 |
QEvent.PaletteChange | 小部件的调色板已更改。 |
QEvent.ParentAboutToChange | 小部件父级即将更改。 |
QEvent.ParentChange | 小部件父级已更改。 |
QEvent.PlatformPanel | 已请求一个特定于平台的面板。 |
QEvent.PlatformSurface | 已创建或即将销毁本机平台表面(QPlatformSurfaceEvent)。 |
QEvent.Polish | 小部件经过抛光处理。 |
QEvent.PolishRequest | 应该对小部件进行抛光处理。 |
QEvent.QueryWhatsThis | 如果小部件有"What’s This?"帮助(QHelpEvent),那么它应该接受该事件。 |
QEvent.Quit | 应用程序已退出。 |
QEvent.ReadOnlyChange | 小部件的只读状态已更改。 |
QEvent.RequestSoftwareInputPanel | 一个小部件想要打开一个软件输入面板(SIP)。 |
QEvent.Resize | 小部件的大小已更改(QResizeEvent)。 |
QEvent.ScrollPrepare | 对象需要填写其几何体信息(QScrollPrepareEvent)。 |
QEvent.Scroll | 对象需要滚动到提供的位置(QScrollEvent)。 |
QEvent.Shortcut | 按下子项以进行快捷键处理(QShortcutEvent)。 |
QEvent.ShortcutOverride | 按键输入子项,用于覆盖快捷键处理(QKeyEvent)。当快捷方式即将触发时,ShortcutOverride将发送到活动窗口。这允许客户端(例如小部件)通过接受事件来发出信号,表明他们将自己处理快捷方式。如果接受快捷方式覆盖,则事件将作为正常按键传递到焦点小部件。否则,它会触发快捷操作(如果存在的话)。 |
QEvent.Show | 小部件已显示在屏幕上(QShowEvent)。 |
QEvent.ShowToParent | 已经显示了一个子窗口小部件。 |
QEvent.SockAct | 套接字已激活,用于实现QSocketNotifier。 |
QEvent.StateMachineSignal | 一种传递到状态机的信号(QStateMachine::SignalEvent)。 |
QEvent.StateMachineWrapped | 该事件是另一个事件(QStateMachine::WrappedEvent)的包装器,即包含该事件。 |
QEvent.StatusTip | 请求状态提示(QStatusTipEvent)。 |
QEvent.StyleChange | 小工具的样式已更改。 |
QEvent.TabletMove | 表格移动(QTabletEvent)。 |
QEvent.TabletPress | 表格按下(QTabletEvent)。 |
QEvent.TabletRelease | 表格释放(QTabletEvent). |
QEvent.TabletEnterProximity | 进入表格事件(QTabletEvent),发送至QApplication。 |
QEvent.TabletLeaveProximity | 离开表格事件(QTabletEvent),发送至QApplication。 |
QEvent.TabletTrackingChange | 表格跟踪状态已更改。 |
QEvent.ThreadChange | 对象被移动到另一个线程。这是上一个线程中发送到此对象的最后一个事件。请参见moveToThread()。 |
QEvent.Timer | 定时事件(QTimerEvent)。 |
QEvent.ToolBarChange | 在macOS上切换工具栏按钮。 |
QEvent.ToolTip | 请求了工具提示(QHelpEvent)。 |
QEvent.ToolTipChange | 小部件的工具提示已更改。 |
QEvent.TouchBegin | 触摸屏或触控板事件序列的开始(QTouchEvent)。 |
QEvent.TouchCancel | 取消触摸事件序列(QTouchEvent)。 |
QEvent.TouchEnd | 触摸结束事件序列(QTouchEvent)。 |
QEvent.TouchUpdate | 触摸屏事件(QTouchEvent)。 |
QEvent.UngrabKeyboard | 项目丢失键盘抓取(仅QGraphicsItem)。 |
QEvent.UngrabMouse | 项目丢失鼠标抓取(QGraphicsItem,QQuickItem)。 |
QEvent.UpdateLater | 小部件应该排队等待以后重新绘制。 |
QEvent.UpdateRequest | 应该重新绘制小部件。 |
QEvent.WhatsThis | 小部件应该显示"这是什么?"帮助(QHelpEvent)。 |
QEvent.WhatsThisClicked | 点击了小部件"这是什么?"帮助中的链接。 |
QEvent.Wheel | 鼠标滚轮滚动(QWheelEvent)。 |
QEvent.WinEventAct | 发生了Windows特定的激活事件。 |
QEvent.WindowActivate | 窗口已激活。 |
QEvent.WindowBlocked | 该窗口被模式对话框阻止。 |
QEvent.WindowDeactivate | 窗口已停用。 |
QEvent.WindowIconChange | 窗口的图标已更改。 |
QEvent.WindowStateChange | 窗口的状态(最小化、最大化或全屏)已更改(QWindowStateChangeEvent)。 |
QEvent.WindowTitleChange | 窗口标题已更改。 |
QEvent.WindowUnblocked | 退出模式对话框后,窗口将被取消阻止。 |
QEvent.WinIdChange | 此本机小部件的窗口系统标识符已更改。 |
QEvent.ZOrderChange | 小部件的z顺序已更改。此事件从不发送到顶级窗口。 |
PySide/PyQt 是对 Qt的封装,Qt 程序是事件驱动的,它的每个动作都由幕后的某个事件触发有些事件类型类支持多种动作触发方式,如QMouseEvent 支持鼠标按键按下双击、移动等相关操作。事件来源比较广泛,一些事件来自窗口系统(如QMouseEvent和OKeyEvent),一些事件来自其他来源(如QtimerEvent),有些事件来自应用程序本身。常见的 Qt事件如下。
还有一些常见的 Qt 事件,如 Socket 事件、剪贴板事件、字体改变事件、布局改变事件等。
Qt中所有的事件类型如表所示。
事件类型 | 描 述 |
---|---|
QtGui.QShortcutEvent | QShortcutEvent 类提供了一个在用户按下组合键时生成的事件 |
QtGui.QWindowStateChangeEvent | QWindowStateChangeEvent 类在窗口状态更改之前提供窗口状态 |
QtGui.QTouchEvent | QTouchEvent 类包含描述触摸事件的参数 |
QtGui.QScrollPrepareEvent | 发送 QScrollPrepareEvent类以准备滚动 |
QtGui.QScrollEvent | 滚动时发送 QScrollEvent 类 |
QtGui.QPointingDevice | QPointingDevice类描述了鼠标、触摸或平板电脑事件源自的设备 |
QtGui.QPointingDeviceUniqueId | QPointingDeviceUniqueld标识一个唯一的对象,如标记的令牌或手写 笔,它与定点设备(PointingDevice)一起使用 |
QtGui.QShortcut | QShortcut类用于创建键盘快捷键 |
QtWidgets.QGestureEvent | QGestureEvent 类提供触发手势的描述 |
QtCore.QEvent | QEvent类是所有事件类的基类。事件对象包含参数 |
QtCore.QTimerEvent | QTimerEvent类包含描述计时器事件的参数 |
QtCore.QChildEvent | QChildEvent类包含子对象事件的参数 |
QtCore.QDynamicPropertyChangeEvent | QDynamicPropertyChangeEvent 类包含动态属性更改事件的参数 |
QtCore.QTimer | QTimer类提供重复和单次定时器 |
QtGui.QEnterEvent | QEnterEvent类包含描述输入事件的参数 |
QtGui.QInputEvent | QInputEvent 类是描述用户输入的事件的基类 |
QtGui.QMouseEvent | QMouseEvent类包含描述鼠标事件的参数 |
QtGui.QHoverEvent | QHoverEvent 类包含描述鼠标事件的参数 |
QtGui.QWheelEvent | QWheelEvent类包含描述鼠标滚轮事件的参数 |
QtGui.QKeyEvent | QKeyEvent类描述了一个按键事件 |
QtGui.QFocusEvent | QFocusEvent 类包含小部件焦点事件的参数 |
QtGui.QPaintEvent | QPaintEvent类包含绘制事件的参数 |
QtGui.QMoveEvent | QMoveEvent类包含移动事件的参数 |
QtGui.QExposeEvent | QExposeEvent类包含用于公开事件的参数 |
QtGui.QPlatformSurfaceEvent | QPlatformSurfaceEvent类用于通知本机platform surface相关事件 |
QtGui.QResizeEvent | QResizeEvent类包含调整大小事件的参数 |
QtGui.QCloseEvent | QCloseEvent类包含描述关闭事件的参数 |
QtGui.QIconDragEvent | QIconDragEvent类指示主图标拖动已开始 |
QtGui.QContextMenuEvent | QContextMenuEvent类包含描述上下文菜单事件的参数 |
QtGui.QInputMethodEvent | QInputMethodEvent类为输入法事件提供参数 |
QtGui.QTabletEvent | QTabletEvent 类包含描述平板电脑事件的参数 |
QtGui.QNativeGestureEvent | QNativeGestureEvent类包含描述手势事件的参数 |
QtGui.QDropEvent | QDropEvent类提供了一个在拖放操作完成时发送的事件 |
QtGui.QDragEnterEvent | QDragEnterEvent类提供了一个事件,当拖放操作进入小部件时,该事 件被发送到小部件 |
QtGui.QDragMoveEvent | QDragMoveEvent类提供了一个在拖放操作正在进行时发送的事件 |
QtGui.QDragLeaveEvent | QDragLeaveEvent类提供了一个事件,当拖放操作离开小部件时,该事 件被发送到小部件 |
QtGui.QHelpEvent | QHelpEvent 类提供了一个事件,用于请求有关小部件中特定点的有用 信息 |
QtGui.QStatusTipEvent | QStatusTipEvent类提供了一个用于在状态栏中显示消息的事件 |
QtGui.QWhatsThisClickedEvent | QWhatsThisClickedEvent 类提供了一个事件,可以用于处理"这是什 么?"中的超链接、文本 |
QtGui.QActionEvent | QActionEvent类提供了在添加、删除或更改QAction时生成的事件 |
QtGui.QHideEvent | QHideEvent类提供了一个在小部件隐藏后发送的事件 |
QtGui.QShowEvent | QShowEvent类提供了在显示小部件时发送的事件 |
QtGui.QFileOpenEvent | QFileOpenEvent类提供了一个事件,当请求打开文件或 URL时将发送 该事件 |
QtGui.QShortcutEvent | QShortcutEvent类提供了一个在用户按下组合键时生成的事件 |
QtGui.QWindowStateChangeEvent | QWindowStateChangeEvent类在窗口状态更改之前提供窗口状态 |
QtGui.QTouchEvent | QTouchEvent类包含描述触摸事件的参数 |
QtGui.QScrollPrepareEvent | 发送QScrollPrepareEvent类以准备滚动 |
QtGui.QScrollEvent | 滚动时发送 QScrollEvent类 |
QtGui.QPointingDevice | QPointingDevice 类描述了鼠标、触摸或平板电脑事件源自的设备 |
QtGui.QPointingDeviceUniqueId | QPointingDeviceUniqueld标识一个唯一的对象,如标记的令牌或手写 笔,它与定点设备(PointingDevice)一起使用 |
QtGui.QShortcut | QShortcut类用于创建键盘快捷键 |
QtWidgets.QGestureEvent | QGestureEvent 类提供触发手势的描述 |
窗口或控件中用于常用事件的处理函数及参数类型如表所示,传递的参数是对应类的实例对象,参数所代表的类的使用方法在后续内容中进行介绍
常用事件的处理函数及参数类型 | 说 明 |
---|---|
actionEvent(QActionEvent) | 当增加、插人、删除QAction时调用该函数 |
changeEvent(QEvent) | 状态发生改变时调用该函数,事件类型包括: QEvent.ToolBarChange QEvent.ActivationChange QEvent.EnabledChange QEvent.FontChange QEvent.StyleChange QEvent.PaletteChange QEvent.WindowTitleChange QEvent.IconTextChange QEvent.ModifiedChange QEvent.MouseTrackingChange QEvent.ParentChange QEvent.WindowStateChange QEvent.LanguageChange QEvent.LocaleChange QEvent.LayoutDirectionChange QEvent.ReadOnlyChange |
childEvent(QChildEvent) | 容器控件中添加或移除控件时调用该函数 |
closeEvent(QCloseEvent) | 关闭窗口时调用该函数 |
contextMenuEvent(QContextMenuEvent) | 当窗口或控件的contextMenuPolicy 属性值是 Qt.DefaultContextMenu,单击右键弹出右键菜单时调用该函数 |
dragEnterEvent(QDragEnterEvent) | 用鼠标拖拽物体进入窗口或控件时调用该函数 |
dragLeaveEvent(QDragLeaveEvent) | 用鼠标拖拽物体离开窗口或控件时调用该函数 |
dragMoveEvent(QDragMoveEvent) | 用鼠标拖拽物体在窗口或控件中移动时调用该函数 |
dropEvent(QDropEvent) | 用鼠标拖拽物体在窗口或控件中释放时调用该函数 |
enterEvent(QEnterEvent) | 光标进人窗口或控件时调用该函数 |
focusInEvent(QFocusEvent) | 用键盘使窗口或控件获得焦点时调用该函数 |
focusOutEvent(QFocusEvent) | 用键盘使窗口或控件失去焦点时调用该函数 |
hideEvent(QHideEvent) | 隐藏或最小化窗口时调用该函数 |
inputMethodEvent(QInputMethodEvent) | 输人方法的状态发生改变时调用该数 |
keyPressEvent(QKeyEvent) | 按下键盘的按键时调用该函数 |
keyReleaseEvent(QKeyEvent) | 释放键盘的按键时调用该函数 |
leaveEvent(QEvent) | 光标离开窗口或控件时调用该函数 |
mouseDoubleClickEvent(QMouseEvent) | 双击鼠标时调用该函数 |
mouseMoveEvent(QMouseEvent) | 光标在窗口或控件中移动时调用该函数 |
mousePressEvent(QMouseEvent) | 按下鼠标的按键时调用该函数 |
mouseReleaseEvent(QMouseEvent) | 释放鼠标的按键时调用该函数 |
moveEvent(QMoveEvent) | 移动窗口或控件时调用该函数 |
paintEvent(QPaintEvent) | 控件或窗口需要重新绘制时调用该函数 |
resizeEvent(QResizeEvent) | 窗口或控件的尺寸(长度或宽度)发生改变时调用该函数 |
showEvent(QShowEvent) | 显示窗口或从最小化恢复到原窗口状态时调用该函数 . |
tabletEvent(QTabletEvent) | 平板电脑处理事件 |
timerEvent(QTimerEvent) | 用窗口或控件的 startTimer(interval: int,timerType:Qt.CoarseTimer)方法启动一个定时器时调用该函数 |
wheelEvent(QWheelEvent) | 转动鼠标的滚轮时调用该函数 |
每个窗口或控件的功能是不同的,因此窗口和控件的事件也不同,用于处理事件的函数也不同。
下面介绍的窗口或常用控件的事件处理函数如表所示。要调用窗口或控件的事件处理函数,需要继承窗口类或控件类创建其子类,在子类中重写事件处理函数。
窗口或控件 | 窗口或控件的事件处理函数 |
---|---|
QWidget | actionEvent() changeEvent() closeEvent() contextMenuEvent() dragEnterEvent() dragLeaveEvent() dragMoveEvent() dropEvent() enterEvent() focusInEvent() focusOutEvent() hideEvent() inputMethodEvent() keyPressEvent() leaveEvent() keyReleaseEvent() mouseDoubleClickEvent() mouseMoveEvent() showEvent() mousePressEvent() mouseReleaseEvent() moveEvent() paintEvent() event()resizeEvent() tabletEvent() wheelEvent() |
QMainWindo | contextMenuEvent() event() |
QDialog | showEvent() closeEvent() contextMenuEvent() eventFilter() keyPressEvent() resizeEvent() |
QLabel | changeEvent() contextMenuEvent() event() focusInEvent() focusutEvent() keyPressEyent() mouseMoveEvent() mousePressEvent() mouseReleaseEvent() paintEyent() |
QLineEdit | changeEvent() contextMenuEvent() dragEnterEvent() dragleaveEvent() dragMoveEvent() dropEvent() focusInEvent() focusutEvent() paintEvent() inputMethodEvent() keyPressEvent() keyReleaseEvent() mouseMoveEvent() mouseDoubleClickEvent() mousePressEvent() rouseReleaseEvent() |
QTextEdit | changeEvent() contextMenuEvent() dragEnterEvent() dragLeaveEvent() dragMoveEvent() dropEvent() focusInEvent() focusCutEvent() showEvent() inputMethodEvent() keyPressEvent() keyReleaseEvent() resizeEvent() mouseDoubleClickEvent() mouseMoyeEvent() mousePressEvent() paintEvent() mouseReleaseEvent() wheelEvent() |
QPlainTextEdit | changeEvent() contextMenuEvent() dragEnterEvent() dragLeaveEvent() dragMoveEvent() dropEvent() focusInEvent() focusOutEvent() paintEvent() inputMethodEvent() keyPressEvent() keyReleaseEvent() resizeEvent() mouseDoubleClickEvent() mouseMoveEvent() mousePressEvent() showEvent() mouseReleaseEvent() wheelEvent() |
QTextBrowser | event() focusOutEvent() keyPressEvent() mouseMoveEvent() paintEvent() mousePressEvent() mouseReleaseEvent() |
QComboBox | changeEvent() contextMenuEvent() focusInEvent() focusOutEvent() hideEvent() inputMethodEvent() keyPressEvent() keyReleaseEvent() musePressEvent() mouseReleaseEvent() paintEvent() resizeEvent() showEvent() wheelEvent() |
QScrollBar | event() contextMenuEvent() hideEvent() mouseMoveEvent() paintEvent() mousePressEvent() mouseReleaseEvent() wheelEvent() |
QSlider | event() mouseMoveEvent() mousePressEvent() mouseReleaseEvent() paintEvent() |
QDial | event() mouseMoveEvent() mousePressEvent() mouseReleaseEvent() paintEvent() resizeEvent() |
QProgressBar | event() paintEvent() |
QPushButton | event() focusInEvent() focusOutEvent() keyPressEvent() mouseMoveEvent() paintEvent() |
QCheckBox | event() mouseMoveEvent() paintEvent() |
QRadioButton | event() mouseMoveEvent() paintEvent() |
OCalendarWidget | event() eventFilter(t) keyPressEvent() mousePressEvent() resizeEvent() |
QLCDNumber | event() paintEvent() |
QDateTimeEdit | focusInEvent() keyPressEvent() mousePressEvent() paintEvent() wheelEvent() |
QGroupBox | changeEvent() childEvent(QChildEvent) event() focusInEvent() resizeEvent() mouseMoveEvent() mousePressEvent() mouseReleaseEvent() paintEvent() |
QFrame | changeEvent() event() paintEvent() |
QScrollArea | event() eventFilter(QObject, QEvent) resizeEvent() |
QTabWidget | changeEvent() event() keyPressEvent() paintEvent() resizeEvent() showEvent() |
QToolBox | changeEvent() closeEvent() event() paintEvent() |
QSplitter | childEvent(QChildEvent) event() eventFilter() paintEvent() resizeEvent() showEvent() timerEvent() viewportEvent() |
QWebEngineView | closeEvent() contextMenuEvent() dragEnterEvent() dragLeaveEvent() dragMoveEvent() dropEvent() event() hideEvent() showEvent() |
QDockWidget | changeEvent() closeEvent() event() paintEvent() |
QMdiArea | childEvent(QChildEvent) event() eventFilter() paintEvent() resizeEvent() showEvent() timerEvent() viewportEvent() |
QMdiSubWindow | changeEvent() childEvent(QChildEvent) closeEvent() contextMenuEvent() event() eventFilter() focusInEvent() focusOutEvent() hideEvent() timerEvent() keyPressEvent() leaveEvent() mouseDoubleClickEvent() mouseMoveEvent() mousePressEvent() mouseReleaseEvent() moveEvent() paintEvent() resizeEvent()showEvent() |
QToolButton | actionEvent() changeEvent() enterEvent() event() leaveEvent() timerEvent() mousePressEvent() mouseReleaseEvent() paintEvent() |
QToolBar | actionEvent() changeEvent() event() paintEvent() |
QMenuBar | actionEvent() changeEvent() event() eventFilter() focusnEvent() leaveEvent() focusOutEvent() keyPressEvent() nouseMoveEvent() mousePressEvent() mouseReleaseEvent() paintEvent() resizeEvent() timerEvent(QTimerEvent) |
QStatusBar | event() paintEvent() resizeEvent() showEvent() |
QTabBar | changeEvent()event() hideEvent() keyPressEvent() mouseDoubleClickEvent() mouseMoveEvent() mousePressEyent() ouseReleaseEvent() paintEyent() resizeEvent() showEvent() timerEyent(QTimerEvent) wheelEvent() |
QListWidget | dropEvent() event() |
QTableWidget | dropEvent() event() |
QTreeWidget | dropEvent() event() |
QListView | dragLeaveEvent() dragMoveEvent() dropEvent() event() mouseMoveEvent() mouseReleaseEvent() paintEvent() resizeEvent() timerEvent(QTimerEvent) wheelEvent() |
QTreeView | changeEvent() dragMoveEvent() keyPressEvent() mouseDoubleClickEvent() mouseMoveEvent() mousePressEvent() mouseReleaseEvent() paintEvent() timerEvent(QTimerEvent) viewportEvent() |
QTableView | paintEyent() timerEvent(QTimerEvent) |
QVideoWidget | event() hideEvent() moveEvent() resizeEvent() showEvent() |
QGraphicsView | contextMenuEvent() dragEnterEvent() dragLeaveEvent() ragMoveEvent() dropEvent() event() focusInEvent() focusOutEvent() inputMethodEvent() keyPressEvent() keyReleaseEvent() mouseDoubleClickEvent() paintEvent() mouseMoveEyent() mousePressEyent() mouseReleaseEvent() resizeEvent() showEvent() viewportEvent() wheelEvent() |
QGraphicsScene | event() focusInEyent() focusOutEvent() keyPressEvent() keyReleaseEvent() eventFilter(QObject, QEvent) inputMethodEvent() helpEvent(QGraphicsSceneHelpEvent) wheelEvent(QGraphicsSceneWheelEvent) contextMenuEvent(QGraphicsSceneContextMenuEvent) dragEnterEyent(QGraphicsSceneragDropEvent) dragleaveEvent(QGraphicsSceneDragDropEvent) dragMoveEvent(QGraphicsSceneDragDropEvent) dropEvent(QGraphicsSceneDragDropEvent) mouseDoubleClickEvent(QCraphicsSceneMouseEvent) mouseMoveEvent(QGraphicsSceneMouseEvent) mousePressEvent(QGraphicsSceneMouseEvent) mouseReleaseEvent(QGraphicsSceneMouseEvent) |
QGraphicsWidget | changeEyent() closeEvent() hideEvent() showEvent() polishEvent() grabKeyboardEvent(QEvent) grabMouseEvent(QEvent) ungrabKeyboardEventQEvent) ungrabMouseEvent(QEvent) windowFrameEvent(QEvent) moveEventQGraphicsSceneMoveEvent) rasizeEvent(QGraphicsSceneResizeEvent) |
QGraphicsItem | focusInEvent() focusOutEvent() inputMethodEvent() keyPressEvent() QEvent() keyReleaseEvent() sceneEvent() dropEvent(QGraphicsSceneDragDropEvent) sceneEventFilter(QGraphicsItem, QEvent) wheelEvent(QGraphicsSceneWheelEvent) contextMenuEvent(QGraphicsSceneContextMenuEvent) dragEnterEvent(QGraphicsSceneDragDropEvent) dragLeaveEvent(QGraphicsSceneDragDropEvent) dragMoveEvent(QGraphicsSceneDragDropEvent) hoverEnterEvent(QGraphicsSceneHoverEvent) hoverLeaveEvent(QGraphicsSceneHoverEvent) hoverMoveEvent(QGraphicsSceneHoverEvent) mouseDoubleClickEvent(GraphicsSceneMouseEvent) mouseMoveEvent(QGraphicsSceneMouseEvent) mousePressEvent(QGraphics-SceneMouseEvent) mouseReleaseEvent(QGraphicsSceneMoGseEvent) |
当GUI应用程序捕捉到事件发生后,会首先将其发送到 QWidget 或子类的event(QEvent)函数中进行数据处理,如果没有重写event()函数进行事件处,理事件将会分发到事件默认的处理函数中,因此event()函数是事件的集散地。
如果重写了 event()函数当event()函数的返回值是True 时,表示事件已经处理完毕事件不会再发送给其他处理函数;当event()函数的返回值是 False时,表示事件还没有处理完毕。event()函数可以截获某些类型的事件,并处理事件
下面的程序是将上节中的例子做了改动将鼠标的单击事件放到event()函数中进行处理,只截获QEvent.MouseButtonPress事件,通过 super()函数调用父类的 event()函数其他类型的事件仍交由QWidget 的event()函数处理和分发。
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/1 21:18
# File_name: 02-event()函数.py
import sys
from PySide6.QtWidgets import QApplication,QWidget,QLineEdit
from PySide6.QtCore import QEvent,Qt
class MyWindow(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.resize(500,500)
self.lineEdit = QLineEdit(self)
self.lineEdit.setGeometry(0,0,500,30)
def event(self,even): # 重写event函数
if even.type()== QEvent.MouseButtonPress: # 按键的情况
template1 ="单击点的窗口坐标是x:{} y:{}"
template2 ="单击点的屏幕坐标是x:{} y:{}"
if even.button()== Qt.LeftButton: # button()获取键或右键
string = template1.format(even.position().x(),even.position().y())# x()和()获取窗口坐标
self.lineEdit.setText(string)
return True
elif even.button()== Qt.RightButton: # globalX()和globalY()获取全局坐标
string = template2.format(even.globalPosition().x(),even.globalPosition().y())
self.lineEdit.setText(string)
return True
else: # 按中键的情况
return True
else: # 对于不是按鼠标键的事件,交给 owidget 来处理
finished = super().event(even)# super()函数调用父类丽数
return finished
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
win.show()
sys.exit(app.exec())
PySide/PyQt 提供了如下 5 种事件处理和过滤的方法(由弱到强),其中前两种方法使用得比较频繁。在一般情况下,应尽量避免使用第 3~5 种方法,因为使用这3 种方法不仅会增加代码的复杂性,还会降低程序性能。
重新实现事件函数
mousePressEvent()、keyPressEvent()和 paintEvent()是常规的事件处理方法
重新实现 QObject.event()函数
该方法一般用在 PySide/PyQt 没有提供事件处理函数的情况下,使用这种方法可以新增事件。
安装事件过滤器
如果对 QObject 调用 installEventFilter,则相当于为这个 QObject 安装了一个事件过滤器。
QObject 的全部事件都会先传递到事件过滤函数eventFilter()中,在这个函数中可以抛弃或修改这些事件,如可以对自已感兴趣的事件使用自定义的事件处理机制,对其他事件使用默认的事件处理机制。
由于这种方法会对调用 installEventFilter 的所有 QObject的事件进行过滤,因此如果要过滤的事件比较多,就会降低程序的性能。
在QApplication 中安装事件过滤器
这种方法比上一种方法更强大
QApplication 的事件过滤器将捕获 QObject 的全部事件,并且先获得该事件。
也就是说,在将事件发送给其他任何一个事件过滤器之前(就是在第 3 种方法之前),都会先发送给 QApplication 的事件过滤器。
重新实现QApplication的 notify0函数
PySide/PyQt使用notify0函数来分发事件。要想在任何事件处理器之前捕获事件,唯的方法就是重新实现 QApplication 的 notify0函数。在实践中,只有调试时才会使用这种方法。
这个例子比较经典,涉及提到的前两种方法,并且内容很丰富,基本上包含对事件处理的绝大部分需求
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/1 23:00
# File_name: demo.py
import sys
from PySide6.QtCore import(QEvent,QTimer,Qt)
from PySide6.QtWidgets import(QApplication,QMenu,QWidget)
from PySide6.QtGui import QPainter
class Widget(QWidget):
def __init__(self,parent=None):
super(Widget,self).__init__(parent)
self.justDoubleClicked = False
self.key =""
self.text =""
self.message =""
self.resize(400,300)
self.move(100,100)
self.setWindowTitle("Events")
QTimer.singleShot(0,self.giveHelp)# 避免窗口大小重绘事件的影响,可以把参数0改变成3000(3秒),然后在运行,就可以明白这行代码的意思。
def giveHelp(self):
self.text ="请点击这里触发追踪鼠标功能"
self.update()# 重绘事件,也就是触发paintEvent函数。
# 重新实现关闭事件
def closeEvent(self,event):
print("Closed")
# 重新实现上下文菜单事件
def contextMenuEvent(self,event):
menu = QMenu(self)
oneAction = menu.addAction("&One")
twoAction = menu.addAction("&Two")
oneAction.triggered.connect(self.one)
twoAction.triggered.connect(self.two)
if not self.message:
menu.addSeparator()
threeAction = menu.addAction("Thre&e")
threeAction.triggered.connect(self.three)
menu.exec(event.globalPos())
# 上下文菜单槽函数
def one(self):
self.message ="Menu option One"
self.update()
def two(self):
self.message ="Menu option Two"
self.update()
def three(self):
self.message ="Menu option Three"
self.update()
# 重新实现绘制事件
def paintEvent(self,event):
text = self.text
i = text.find("\n\n")
if i >= 0:
text = text[0:i]
if self.key: # 若触发了键盘按钮,则在文本信息中记录这个按钮信息。
text +="\n\n你按下了: {0}".format(self.key)
painter = QPainter(self)
painter.setRenderHint(QPainter.TextAntialiasing)
painter.drawText(self.rect(),Qt.AlignCenter,text)# 绘制信息文本的内容
if self.message: # 若消息文本存在则在底部居中绘制消息,5秒钟后清空消息文本并重绘。
painter.drawText(self.rect(),Qt.AlignBottom | Qt.AlignHCenter,
self.message)
QTimer.singleShot(5000,self.clearMessage)
QTimer.singleShot(5000,self.update)
# 清空消息文本的槽函数
def clearMessage(self):
self.message =""
# 重新实现调整窗口大小事件
def resizeEvent(self,event):
self.text ="调整窗口大小为: QSize({0},{1})".format(
event.size().width(),event.size().height())
self.update()
# 重新实现鼠标释放事件
def mouseReleaseEvent(self,event):
# 若鼠标释放为双击释放,则不跟踪鼠标移动
# 若鼠标释放为单击释放,则需要改变跟踪功能的状态,如果开启跟踪功能的话就跟踪,不开启跟踪功能就不跟踪
if self.justDoubleClicked:
self.justDoubleClicked = False
else:
self.setMouseTracking(not self.hasMouseTracking())# 单击鼠标
if self.hasMouseTracking():
self.text ="开启鼠标跟踪功能.\n"+ \
"请移动一下鼠标!\n"+ \
"单击鼠标可以关闭这个功能"
else:
self.text ="关闭鼠标跟踪功能.\n"+ \
"单击鼠标可以开启这个功能"
self.update()
# 重新实现鼠标移动事件
def mouseMoveEvent(self,event):
if not self.justDoubleClicked:
globalPos = self.mapToGlobal(event.position())# 窗口坐标转换为屏幕坐标
self.text = f"鼠标位置: 窗口坐标为:QPoint({0},{1})屏幕坐标为:QPoint({2},{3})".format(event.position().x(),event.position().y(),globalPos.x(),globalPos.y())
self.update()
# 重新实现鼠标双击事件
def mouseDoubleClickEvent(self,event):
self.justDoubleClicked = 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()
if self.key:
self.key = self.key
self.update()
else:
QWidget.keyPressEvent(self,event)
# 重新实现其他事件,适用于PyQt没有提供该事件的处理函数的情况,Tab键由于涉及焦点切换,不会传递给keyPressEvent,因此,需要在这里重新定义。
def event(self,event):
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)
form = Widget()
form.show()
app.exec()
下面对本案例的几个关键点进行说明。
一是类的建立。
创建text和message 两个变量,使用paintEvent()函数把它们输出到窗口中。
update()函数的作用是更新窗口。由于在窗口更新过程中会触发一次 paintEvent()函数. paintEvent()是窗口基类QWidget 的内部函数因此在本案例中update()函数的作用等同于paintEvent()函数的作用。代码如下:
class Widget(QWidget):
def __init__(self,parent=None):
super(Widget,self).__init__(parent)
self.justDoubleClicked = False
self.key =""
self.text =""
self.message =""
self.resize(400,300)
self.move(100,100)
self.setWindowTitle("Events")
QTimer.singleShot(0,self.giveHelp)# 避免窗口大小重绘事件的影响,可以把参数0改变成3000(3秒),然后在运行,就可以明白这行代码的意思。
def giveHelp(self):
self.text ="请点击这里触发追踪鼠标功能"
self.update()# 重绘事件,也就是触发paintEvent函数。
二是重新实现窗口关闭事件与上下文菜单事件
上下文菜单事件主要影响 message变量的结果,paintEvent()函数负责把这个变量在窗口底部输出。代码如下:
# 重新实现关闭事件
def closeEvent(self,event):
print("Closed")
# 重新实现上下文菜单事件
def contextMenuEvent(self,event):
menu = QMenu(self)
oneAction = menu.addAction("&One")
twoAction = menu.addAction("&Two")
oneAction.triggered.connect(self.one)
twoAction.triggered.connect(self.two)
if not self.message:
menu.addSeparator()
threeAction = menu.addAction("Thre&e")
threeAction.triggered.connect(self.three)
menu.exec(event.globalPos())
# 上下文菜单槽函数
def one(self):
self.message ="Menu option One"
self.update()
def two(self):
self.message ="Menu option Two"
self.update()
def three(self):
self.message ="Menu option Three"
self.update()
绘制事件是代码的核心事件,它的主要作用是时刻跟踪 text 与 message 这两个变量并把 text 变量的内容绘制到窗口的中部,把 message 变量的内容绘制到窗口的底部(保持 5秒后就会被清空)。代码如下:
# 重新实现绘制事件
def paintEvent(self,event):
text = self.text
i = text.find("\n\n")
if i >= 0:
text = text[0:i]
if self.key: # 若触发了键盘按钮,则在文本信息中记录这个按钮信息。
text +="\n\n你按下了: {0}".format(self.key)
painter = QPainter(self)
painter.setRenderHint(QPainter.TextAntialiasing)
painter.drawText(self.rect(),Qt.AlignCenter,text)# 绘制信息文本的内容
if self.message: # 若消息文本存在则在底部居中绘制消息,5秒钟后清空消息文本并重绘。
painter.drawText(self.rect(),Qt.AlignBottom | Qt.AlignHCenter,self.message)
QTimer.singleShot(5000,self.clearMessage)
QTimer.singleShot(5000,self.update)
# 清空消息文本的槽函数
def clearMessage(self):
self.message =""
三是重新实现调整窗口大小事件,代码如下:
# 重新实现调整窗口大小事件
def resizeEvent(self,event):
self.text ="调整窗口大小为: QSize({0},{1})".format(
event.size().width(),event.size().height())
self.update()
重新实现鼠标释放事件。若为双击释放,则不跟踪鼠标移动;若为单击释放,则需要改变跟踪功能的状态,如果开启跟踪功能就跟踪,否则不跟踪。代码如下:
# 重新实现鼠标释放事件
def mouseReleaseEvent(self,event):
# 若鼠标释放为双击释放,则不跟踪鼠标移动
# 若鼠标释放为单击释放,则需要改变跟踪功能的状态,如果开启跟踪功能的话就跟踪,不开启跟踪功能就不跟踪
if self.justDoubleClicked:
self.justDoubleClicked = False
else:
self.setMouseTracking(not self.hasMouseTracking())# 单击鼠标
if self.hasMouseTracking():
self.text ="开启鼠标跟踪功能.\n"+ \
"请移动一下鼠标!\n"+ \
"单击鼠标可以关闭这个功能"
else:
self.text ="关闭鼠标跟踪功能.\n"+ \
"单击鼠标可以开启这个功能"
self.update()
重新实现鼠标移动事件与鼠标双击事件,代码如下
# 重新实现鼠标移动事件
def mouseMoveEvent(self,event):
if not self.justDoubleClicked:
globalPos = self.mapToGlobal(event.position())# 窗口坐标转换为屏幕坐标
self.text = f"鼠标位置: 窗口坐标为:QPoint({0},{1})屏幕坐标为:QPoint({2},{3})".format(event.position().x(),event.position().y(),globalPos.x(),globalPos.y())
self.update()
# 重新实现鼠标双击事件
def mouseDoubleClickEvent(self,event):
self.justDoubleClicked = 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()
if self.key:
self.key = self.key
self.update()
else:
QWidget.keyPressEvent(self,event)
第2种事件处理方法是重载 event()函数。对于窗口来说,所有的事件都会传递给Event()函数,该函数会根据事件的类型把事件分配给不同的函数进行处理。
例如,绘图事件会交给paintEvent()函数处理,鼠标移动事件会交给mouseMoveEvent()函数处理,键盘按下事件会交给keyPressEvent()函数处理有一种特殊情况是对Tab键的触发行为Event()函数对 Tab 键的处理机制是把焦点从当前窗口控件的位置切换到 Tab 键次序中下一个窗口控件的位置,并返回 True,而不是交给 keyPressEvent()函数处理。
因此,这里需要在event()函数中重新改写按下 Tab 键的处理逻辑,使它与键盘上普通的键没有什么不同。代码如下:
# 重新实现其他事件,适用于PyQt没有提供该事件的处理函数的情况,Tab键由于涉及焦点切换,不会传递给keyPressEvent,因此,需要在这里重新定义。
def event(self,event):
if(event.type()== QEvent.KeyPress and
event.key()== Qt.Key_Tab):
self.key ="在event()中捕获Tab键"
self.update()
return True
return QWidget.event(self,event)
安装事件过滤器例子
# -*- coding: utf-8 -*-
from PySide6.QtGui import *
from PySide6.QtCore import *
from PySide6.QtWidgets import *
import sys
import os
os.chdir(os.path.dirname(__file__))
class EventFilter(QDialog):
def __init__(self,parent=None):
super(EventFilter,self).__init__(parent)
self.setWindowTitle("事件过滤器")
self.label1 = QLabel("请点击")
self.label2 = QLabel("请点击")
self.label3 = QLabel("请点击")
self.LabelState = QLabel("test")
self.image1 = QImage("images/cartoon1.ico")
self.image2 = QImage("images/cartoon1.ico")
self.image3 = QImage("images/cartoon1.ico")
self.width = 600
self.height = 300
self.resize(self.width,self.height)
self.label1.installEventFilter(self)
self.label2.installEventFilter(self)
self.label3.installEventFilter(self)
mainLayout = QGridLayout(self)
mainLayout.addWidget(self.label1,500,0)
mainLayout.addWidget(self.label2,500,1)
mainLayout.addWidget(self.label3,500,2)
mainLayout.addWidget(self.LabelState,600,1)
self.setLayout(mainLayout)
def eventFilter(self,watched,event):
if watched == self.label1: # 只对label1的点击事件进行过滤,重写其行为,其他的事件会被忽略
if event.type()== QEvent.MouseButtonPress: # 这里对鼠标按下事件进行过滤,重写其行为
mouseEvent = QMouseEvent(event)
if mouseEvent.buttons()== Qt.LeftButton:
self.LabelState.setText("按下鼠标左键")
elif mouseEvent.buttons()== Qt.MiddleButton:
self.LabelState.setText("按下鼠标中间键")
elif mouseEvent.buttons()== Qt.RightButton:
self.LabelState.setText("按下鼠标右键")
'''转换图片大小'''
transform = QTransform()
transform.scale(0.5,0.5)
tmp = self.image1.transformed(transform)
self.label1.setPixmap(QPixmap.fromImage(tmp))
if event.type()== QEvent.MouseButtonRelease: # 这里对鼠标释放事件进行过滤,重写其行为
self.LabelState.setText("释放鼠标按钮")
self.label1.setPixmap(QPixmap.fromImage(self.image1))
return QDialog.eventFilter(self,watched,event)# 其他情况会返回系统默认的事件处理方法。
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = EventFilter()
dialog.show()
app.exec()
如果使用事件过滤器,那么关键是做好两步。
对要过滤的控件设置installEventFilter,这些控件的所有事件都会被eventFilter0函数接收并处理。
installEventFilter 的使用方法如下:
self.label1.installEventFilter(self)
self.label2.installEventFilter(self)
self.label3.installEventFilter(self)
在 eventFilter()函数中处理这些控件的事件信息。
下面的代码表示这个过滤器只对 label1 的事件进行处理,并且只处理它的鼠标按下事件(MouseButtonPress)和鼠标释放事件(MouseButtonRelease):
def eventFilter(self,watched,event):
if watched == self.label1: # 只对label1的点击事件进行过滤,重写其行为,其他的事件会被忽略
if event.type()== QEvent.MouseButtonPress: # 这里对鼠标按下事件进行过滤,重写其行为
mouseEvent = QMouseEvent(event)
if mouseEvent.buttons()== Qt.LeftButton:
self.LabelState.setText("按下鼠标左键")
elif mouseEvent.buttons()== Qt.MiddleButton:
self.LabelState.setText("按下鼠标中间键")
elif mouseEvent.buttons()== Qt.RightButton:
self.LabelState.setText("按下鼠标右键")
'''转换图片大小'''
transform = QTransform()
transform.scale(0.5,0.5)
tmp = self.image1.transformed(transform)
self.label1.setPixmap(QPixmap.fromImage(tmp))
if event.type()== QEvent.MouseButtonRelease: # 这里对鼠标释放事件进行过滤,重写其行为
self.LabelState.setText("释放鼠标按钮")
self.label1.setPixmap(QPixmap.fromImage(self.image1))
return QDialog.eventFilter(self,watched,event)# 其他情况会返回系统默认的事件处理方法。
需要注意如下4行代码:
'''转换图片大小'''
transform = QTransform()
transform.scale(0.5,0.5)
tmp = self.image1.transformed(transform)
self.label1.setPixmap(QPixmap.fromImage(tmp))
这4行代码表示如果按下鼠标按键,就会对 label1 装载的图片进行缩放(长和宽各缩放为原来的一半)。
QApplication 中安装事件过滤器例子
# -*- coding: utf-8 -*-
from PySide6.QtGui import *
from PySide6.QtCore import *
from PySide6.QtWidgets import *
import sys
import os
os.chdir(os.path.dirname(__file__))
class EventFilter(QDialog):
def __init__(self,parent=None):
super(EventFilter,self).__init__(parent)
self.setWindowTitle("事件过滤器")
self.label1 = QLabel("请点击")
self.label2 = QLabel("请点击")
self.label3 = QLabel("请点击")
self.LabelState = QLabel("test")
self.image1 = QImage("images/cartoon1.ico")
self.image2 = QImage("images/cartoon1.ico")
self.image3 = QImage("images/cartoon1.ico")
self.width = 600
self.height = 300
self.resize(self.width,self.height)
# self.label1.installEventFilter(self)
# self.label2.installEventFilter(self)
# self.label3.installEventFilter(self)
mainLayout = QGridLayout(self)
mainLayout.addWidget(self.label1,500,0)
mainLayout.addWidget(self.label2,500,1)
mainLayout.addWidget(self.label3,500,2)
mainLayout.addWidget(self.LabelState,600,1)
self.setLayout(mainLayout)
def eventFilter(self,watched,event):
print(type(watched))
if watched == self.label1: # 只对label1的点击事件进行过滤,重写其行为,其他的事件会被忽略
if event.type()== QEvent.MouseButtonPress: # 这里对鼠标按下事件进行过滤,重写其行为
mouseEvent = QMouseEvent(event)
if mouseEvent.buttons()== Qt.LeftButton:
self.LabelState.setText("按下鼠标左键")
elif mouseEvent.buttons()== Qt.MidButton:
self.LabelState.setText("按下鼠标中间键")
elif mouseEvent.buttons()== Qt.RightButton:
self.LabelState.setText("按下鼠标右键")
'''转换图片大小'''
transform = QTransform()
transform.scale(0.5,0.5)
tmp = self.image1.transformed(transform)
self.label1.setPixmap(QPixmap.fromImage(tmp))
if event.type()== QEvent.MouseButtonRelease: # 这里对鼠标释放事件进行过滤,重写其行为
self.LabelState.setText("释放鼠标按钮")
self.label1.setPixmap(QPixmap.fromImage(self.image1))
return QDialog.eventFilter(self,watched,event)# 其他情况会返回系统默认的事件处理方法。
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = EventFilter()
app.installEventFilter(dialog)
dialog.show()
app.exec()
第4种事件处理方法(在 QApplication 中安装事件过滤器)的使用也非常简单,与第 3 种事件处理方法相比,只需要简单地修改两处代码即可。
屏蔽3个label 标签控件的 installEventFilter 的代码
# self.label1.installEventFilter(self)
# self.label2.installEventFilter(self)
# self.label3.installEventFilter(self)
对于在 QApplication 中安装 installEventFilter,下面的代码表示 dialog 的所有事件都要经过 EventFilter()函数的处理,而不仅仅是3个标签控件的事件:
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = EventFilter()
app.installEventFilter(dialog)
dialog.show()
app.exec()
为了更好地展示第4种方法与第3种方法的区别,这里在eventFilter0函数中添加了如下代码:
def eventFilter(self,watched,event):
print(type(watched))
"""输出如下
...
"""
提到的第5种方法(重写QApplication 的 notify()函数)在实际中基本上用不到,所以这里不再介绍。