警告
本节包含从C++自动翻译到Python的代码片段,可能包含错误。
小部件和图形视图中的手势¶
Qt 手势编程支持的概述
Qt 包含一个手势编程框架,该框架能够从一系列事件中形成手势,独立于所使用的输入方法。手势可以是鼠标的特定移动、触摸屏操作或来自其他来源的一系列事件。输入的性质、手势的解释和采取的操作由开发者决定。
概述¶
QGesture 是 Qt 手势框架中的核心类,提供了用户执行手势信息的容器。QGesture 暴露了提供所有手势通用信息的属性,并且这些属性可以扩展以提供特定手势的额外信息。常见的平移、捏合和滑动手势由专门的类表示:QPanGesture、QPinchGesture 和 QSwipeGesture。
开发者还可以通过子类化和扩展QGestureRecognizer类来实现新的手势。添加对新手势的支持涉及实现代码以从输入事件中识别手势。这在创建您自己的手势识别器部分中有描述。
使用标准手势与部件¶
手势可以为QWidget和QGraphicsObject子类的实例启用。在整个文档中,接受手势输入的对象被称为目标对象。
要为目标对象启用手势,请调用其grabGesture()或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状态的手势。
忽略手势将意味着该手势将不再向你提供。它也将提供给父部件或项目。
当手势处于开始状态并且被接受时,调用 setGestureCancelPolicy() 可能会导致其他手势被取消。
使用CancelAllInContext取消手势将导致所有状态下的手势被取消,除非它们被明确接受。这意味着子部件上的活动手势将被取消。这也意味着如果小部件忽略了它们,那么在同一个QGestureEvent中传递的手势也将被取消。这可以是一种有用的方式来过滤掉除你感兴趣的手势之外的所有手势。
事件处理示例¶
为了方便起见,Image Gestures Example 重新实现了通用的 event() 处理函数,并将手势事件委托给专门的 gestureEvent() 函数:
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 可以处理任意数量的触摸点,并允许应用程序开发者编写自定义的手势识别代码。