小工具和图形视图中的手势

Qt 包含一个用于手势编程的框架,它能够通过一系列事件形成手势,而与所使用的输入方法无关。手势可以是鼠标的特定移动、触摸屏操作或其他来源的一系列事件。输入的性质、对手势的解释和采取的行动都由开发人员决定。

概述

QGesture QGesture 公开了提供所有手势通用信息的属性,这些属性还可扩展以提供额外的特定手势信息。常用的平移、捏合和轻扫手势由专门的类来表示:、 和 。QPanGesture QPinchGesture QSwipeGesture

开发人员还可以通过子类化和扩展QGestureRecognizer 类来实现新的手势。要添加对新手势的支持,需要执行代码来识别输入事件中的手势。创建自己的手势识别器"部分将对此进行介绍。

在小工具中使用标准手势

可以为QWidgetQGraphicsObject 子类的实例启用手势。接受手势输入的对象在整个文档中称为目标对象

要为目标对象启用手势,请调用其QWidget::grabGesture() 或QGraphicsObject::grabGesture() 函数,并在参数中说明所需的手势类型。标准类型由Qt::GestureType 枚举定义,包括许多常用手势。

for (Qt::GestureType gesture : gestures)
    grabGesture(gesture);

在上述代码中,手势是在目标对象本身的构造函数中设置的。

处理事件

当用户执行手势时,QGestureEvent 事件将传递给目标对象,这些事件可通过重新实现部件的QWidget::event() 处理函数或图形对象的QGraphicsItem::sceneEvent() 来处理。

由于一个目标对象可以订阅不止一种手势类型,因此QGestureEvent 可以包含不止一个QGesture ,表示有几种可能的手势同时处于活动状态。这就需要小工具来决定如何处理这些多重手势,并选择是否取消其中一些手势,转而使用其他手势。

QGestureEvent 对象中包含的每个QGesture 都可以被单独或全部接受()或忽略()。此外,还可以使用多个获取器查询单个QGesture 数据对象(状态)。

事件处理的标准程序

QGesture 到达您的 widget 时,默认情况下会被接受。不过,好的做法是始终明确接受或拒绝一个手势。一般规则是,如果您接受一个手势,那么您就在使用它。如果忽略它,则表示对它不感兴趣。忽略一个手势可能意味着它被提供给另一个目标对象,或者被取消。

每个QGesture 都会经历几种状态;有一种明确定义的方法可以改变状态,通常用户输入是状态改变的原因(例如通过开始和停止交互),但小工具也可以导致状态改变。

当一个特定的QGesture 首次传送到一个部件或图形项目时,它将处于Qt::GestureStarted 状态。此时处理手势的方式会影响以后是否能与之交互。

  • 接受手势意味着 Widget 会对手势采取行动,随后会出现 Qt::GestureUpdatedstate 的手势。
  • 忽略手势意味着手势将不再提供给你。手势也将提供给父部件或项目。
  • 当手势处于开始状态并被接受时,调用 setGestureCancelPolicy() 会导致其他手势被取消。

使用QGesture::CancelAllInContext 取消手势会导致处于任何状态的所有手势被取消,除非它们被明确接受。这意味着子系统上的活动手势也会被取消。这也意味着,如果小部件忽略了在同一个QGestureEvent 中发送的手势,这些手势也会被取消。这也是一种有用的方法,可以过滤掉除你感兴趣的手势之外的所有手势。

事件处理示例

为方便起见,图像手势示例重新实现了一般的event() 处理函数,并将手势事件委托给专门的 gestureEvent() 函数:

bool ImageWidget::event(QEvent *event)
{
    if (event->type() == QEvent::Gesture)
        return gestureEvent(static_cast<QGestureEvent*>(event));
    return QWidget::event(event);
}

交付给目标对象的手势事件可以单独进行检查并适当处理:

bool ImageWidget::gestureEvent(QGestureEvent *event)
{
    qCDebug(lcExample) << "gestureEvent():" << event;
    if (QGesture *swipe = event->gesture(Qt::SwipeGesture))
        swipeTriggered(static_cast<QSwipeGesture *>(swipe));
    else if (QGesture *pan = event->gesture(Qt::PanGesture))
        panTriggered(static_cast<QPanGesture *>(pan));
    if (QGesture *pinch = event->gesture(Qt::PinchGesture))
        pinchTriggered(static_cast<QPinchGesture *>(pinch));
    return true;
}

响应手势只需获取QGestureEvent 发送给目标对象的QGesture 对象,并检查其中包含的信息即可。

void ImageWidget::swipeTriggered(QSwipeGesture *gesture)
{
    if (gesture->state() == Qt::GestureFinished) {
        if (gesture->horizontalDirection() == QSwipeGesture::Left
            || 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() 函数必须返回一个QGestureRecognizer::Result 值,该值表示给定手势和目标对象的识别状态。这将决定是否向目标对象发送手势事件。

自定义手势

如果选择用自定义QGesture 子类来表示手势,则需要重新实现create() 函数,以构建手势类实例,而不是标准的QGesture 实例。或者,您也可以使用标准的QGesture 实例,但在其中添加额外的动态属性,以表达您想要处理的手势的具体细节。

重置手势

如果您使用的自定义手势对象在取消手势时需要重置或进行其他特殊处理,则需要重新实现reset() 函数来执行这些特殊任务。

请注意,QGesture 对象只针对目标对象和手势类型的每种组合创建一次,而且每次用户尝试在目标对象上执行相同的手势类型时,这些对象都可能被重复使用。因此,在每次尝试识别手势后,重新实现reset() 函数进行清理是非常有用的。

使用新的手势识别器

要使用手势识别器,请构建QGestureRecognizer 子类的实例,并通过QGestureRecognizer::registerRecognizer() 向应用程序注册。可以通过QGestureRecognizer::unregisterRecognizer() 删除特定类型手势的识别器。

更多阅读

图像手势示例展示了如何在一个简单的图像查看器应用程序中为部件启用手势。

中的手势Qt Quick

Qt Quick 中没有通用的全局手势识别器;相反,各个组件可以用自己的方式响应触摸事件。例如, 可处理双指手势, 用于单指轻弹内容,而 可处理任意数量的触摸点,并允许应用程序开发人员编写自定义手势识别代码。PinchArea Flickable MultiPointTouchArea

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.