警告
本节包含从C++自动转换为Python的代码片段,可能包含错误。
Widgets和图形视图中的人工智能#
Qt对Gesture编程支持的概述
Qt包含一个用于Gesture编程的框架,该框架能够根据一系列事件构造Gesture,而不依赖于所使用的输入方法。Gesture可以是鼠标的特定移动、触摸屏动作或者来自其他源的一系列事件。输入的性质、Gesture的解释和采取的动作都是开发者的选择。
概述#
QGesture
是Qt Gesture框架的核心类,为用户提供Gesture信息的容器。 QGesture
公开了用于提供所有Gesture的通用信息的属性,并且可以扩展以提供额外的Gesture特定信息。常见的平移、捏合和滑动Gesture由专用类表示:QPanGesture
、QPinchGesture
和 QSwipeGesture
。
开发者也可以通过继承和扩展QGestureRecognizer
来实现新的Gesture。支持新Gesture涉及从输入事件识别Gesture的代码实现。这将在创建您自己的Gesture识别器章节中描述。
在Widget中使用标准Gesture#
可以为QWidget
和QGraphicsObject
子类实例启用Gesture。接受Gesture输入的对象在整个文档中称为目标对象。
要为目标对象启用手势,请使用其grabGesture()
函数,并传递一个描述所需手势类型的参数。标准类型由Qt::GestureType枚举定义,包括许多常用的手势。
for gesture in gestures: grabGesture(gesture)
在上面的代码中,手势是在目标对象的构造函数中设置的。
处理事件##
当用户执行手势时,会向目标对象发送QGestureEvent
事件,并且可以通过重写小部件的event()
处理器函数或图形对象的sceneEvent()
来处理这些事件。
由于一个目标对象可以订阅多种手势类型,QGestureEvent
可以包含多个QGesture
,表示同时有几个可能的手势处于活动状态。此时,小部件需要确定如何处理这些多个手势,并选择是否取消其中一些以便优先处理其他手势。
可以单独接受()或忽略()每个包含在QGestureEvent
对象中的QGesture
,或者全部接受或忽略。此外,您可以使用多个getter查询单个QGesture
数据对象(状态)。
事件处理的标准程序##
默认情况下,当QGesture
到达您的控件时会被接受。然而,始终明确接受或拒绝手势是一个好的做法。一般规则是,如果您接受了一个手势,您正在使用它。如果您忽略它,您不对此感兴趣。忽略手势可能意味着它会被提供给另一个目标对象,或者它会被取消。
每个QGesture
都经过几个状态;状态更改的方式是明确定义的,通常是用户输入(例如通过开始和停止交互)导致状态变化,但控件也可以导致状态变化。
当一个特定的QGesture
(触摸手势)第一次发送到小部件或图形项时,它将处于Qt::GestureStarted状态。此时您处理手势的方式会影响您以后是否可以与之交互。
接受手势意味着小部件将执行该手势,随后将会有Qt::GestureUpdated状态的手势。
忽略手势意味着该手势将不再向您提供。它也将提供给父小部件或图形项。
在起始状态下调用gesturesetGestureCancelPolicy(),并且已接受手势可能会取消其他手势。
使用CancelAllInContext
来取消手势将取消所有状态的手势,除非它们被明确接受。这意味着所有在子对象上的活动手势将被取消。这也意味着,如果小部件忽略它们,则在同一QGestureEvent
中发送的手势将取消。这可以是一种有用的方式来过滤掉除了您感兴趣的手势之外的所有手势。
示例事件处理#
为了方便,Image Gestures Example重写了通用的event()
处理函数,并将手势事件委托给专门的gesturEvent()函数。
def event(self, QEvent event): if event.type() == QEvent.Gesture: return gestureEvent(QGestureEvent(event)) return QWidget.event(event)
可对发送到目标对象的手势事件进行单独检查和处理。
def gestureEvent(self, QGestureEvent event): qCDebug(lcExample) << "gestureEvent():" << event if QGesture swipe = event.gesture(Qt.SwipeGesture): swipeTriggered(QSwipeGesture(swipe)) elif QGesture pan = event.gesture(Qt.PanGesture): panTriggered(QPanGesture(pan)) if QGesture pinch = event.gesture(Qt.PinchGesture): pinchTriggered(QPinchGesture(pinch)) return True
响应用户的手势仅仅是通过获取发送到目标对象的QGestureEvent
中的QGesture
对象,并查看它所包含的信息。
def swipeTriggered(self, gesture): if gesture.state() == Qt.GestureFinished: if (gesture.horizontalDirection() == QSwipeGesture.Left or gesture.verticalDirection() == QSwipeGesture.Up) { qCDebug(lcExample) << "swipeTriggered(): swipe to previous" goPrevImage() else: qCDebug(lcExample) << "swipeTriggered(): swipe to next" goNextImage() update()
在这里,我们检查用户滑动手势的方向并根据此修改小部件的内容。
创建您自己的手势识别器#
支持新的手势需要创建和注册一个新的手势识别器。根据手势识别过程,可能还需要创建一个新手势对象。
要创建新识别器,您需要通过创建自定义识别器类子类化QGestureRecognizer
。这里有一个必须重写和两个可以选择重写的虚拟函数。
过滤输入事件#
必须重写recognize()
函数。这个函数处理并过滤需送往目标对象的输入事件,并确定这些事件是否对应于识别器正在查找的手势。
尽管在此函数中实现了手势识别逻辑,可能使用基于Qt::GestureState枚举的状态机,但您可以在提供的QGesture
对象中保存识别过程状态的持久信息。
您的 recognize() 方法 必须返回一个表示特定手势和目标对象识别状态的 Result
值。这决定了是否将手势事件传递给目标对象。
自定义手势链接到本标题
如果您选择通过自定义的 QGesture 子类来表示手势,您需要重新实现 create() 方法 来构造您手势类实例,而不是标准 QGesture 实例。或者,您可能希望使用标准的 QGesture 实例,但为它们添加额外的动态属性以表达您要处理的手势的特定细节。
重置手势链接到本标题
如果您使用需要重置或特殊处理以取消手势的自定义手势对象,您需要重新实现 reset() 方法 来执行这些特殊任务。
请注意,对于每个目标对象和手势类型的组合,将只创建一次 QGesture 对象,它们可能会在用户尝试在目标对象上执行相同类型的手势时重复使用。因此,重新实现 reset() 方法 以清理每次尝试识别手势后的之前的尝试可能是有用的。
使用新的手势识别器链接到本标题
要使用手势识别器,构造您的 QGestureRecognizer 子类实例,并通过 registerRecognizer() 方法 将其注册到应用程序中。可以卸载特定类型手势的识别器,使用 unregisterRecognizer() 方法。
进一步阅读链接到本标题
图像手势示例 展示了如何在简单的图像查看器应用程序中为小部件启用手势。
Qt Quick 中的手势链接到本标题
Qt Quick 没有通用的全局手势识别器;相反,各个组件可以以自己的方式响应触摸事件。例如,PinchArea 可以处理双指手势,Flickable 用于单指滑动内容,MultiPointTouchArea 可以处理任意数量的触摸点,并允许应用程序开发者编写自定义手势识别代码。