Widget 和圖形視圖中的手勢

Qt 包括手勢編程框架,擁有從獨立於所用輸方法的一係列事件形成手勢的能力。手勢可以是特定鼠標運動,觸摸屏動作,或來自某些其它源的一係列事件。輸入的性質、手勢的解釋及獲取動作由開發者抉擇。

概述

QGesture 是 Qt 手勢框架中心類,提供用戶履行手勢有關信息的容器。 QGesture 暴露瞭賦予所有手勢一般公共信息的特性,且可以擴展這些以提供特定額外手勢信息。常見的平移、捏閤和輕掃手勢由專用類錶示: QPanGesture , QPinchGesture and QSwipeGesture .

開發者還可以實現新手勢通過子類化並擴展 QGestureRecognizer 類。 添加支持新手勢涉及實現從輸入事件識彆手勢的代碼。這的描述在 創建自己的手勢識彆器 章節。

在 Widget 中使用標準手勢

可以啓用手勢為實例化的 QWidget and QGraphicsObject 子類。接受手勢輸入的對象在整個文檔編製被稱為 目標對象 .

要啓用目標對象手勢,調用其 QWidget::grabGesture () 或 QGraphicsObject::grabGesture () 函數采用自變量描述要求的手勢類型。標準類型的定義是通過 Qt::GestureType 枚舉且包括很多常用手勢。

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

以上代碼,手勢是在目標對象本身的構造函數中設置的。

處理事件

當用戶履行手勢時, QGestureEvent 事件會被交付給目標對象,且可以處理這些通過重實現 QWidget::event () 處理程序函數為 Widget 或 QGraphicsItem::sceneEvent () 為圖形對象。

由於一個目標對象可以訂閱多種手勢類型, QGestureEvent 可以包含多個 QGesture ,指示幾個手勢同時活動是可能的。然後由 Widget 確定如何處理這些手勢並選擇,若取消一些手勢代之其它手勢。

每個 QGesture 包含於 QGestureEvent 對象可以單獨或全部一起 accepted() 或 ignored()。此外,可以查詢單個 QGesture 數據對象 (狀態) 使用幾個 getter。

事件處理的標準程序

A QGesture 默認是接受的,當它到達 Widget 時。不管怎樣,好的實踐是始終明確接受 (或拒絕) 手勢。一般規則是,若接受手勢,就會使用它。若忽略,就是對它不感興趣。忽略手勢可能意味著,會將它提供給另一目標對象 (或者它將被取消)。

每個 QGesture 會經曆幾種狀態;有改變狀態的良好定義方式,通常,用戶輸入是狀態變化的原因 (例如:通過啓動和停止交互),但 Widget 也可能導緻狀態改變。

首先,特定 QGesture 被交付給 Widget 或圖形項,它會在 Qt::GestureStarted 狀態。 此時處理手勢的方式,會影響稍後是否可以與之交互。

  • 接受手勢意味著 Widget 作用於手勢,且手勢隨後具有 Qt::GestureUpdatedstate。
  • 忽略手勢將意味著不會再提供手勢。還會將它提供給父級 Widget 或項。
  • 調用手勢的 setGestureCancelPolicy() 當其處於啓動狀態時,且接受還會導緻其它手勢被取消。

使用 QGesture::CancelAllInContext 來取消手勢將導緻所有手勢被取消,在任何狀態下都會被取消,除非明確接受它們。這意味著,將取消子級的活動手勢。也意味著,手勢的交付是在同一 QGestureEvent 會被取消若 Widget 忽略它們。這是可以過濾掉所有手勢的有用方式,除感興趣的手勢外。

事件處理範例

為方便起見, 圖像手勢範例 重實現一般 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;
}
					

手勢響應問題隻需獲得 QGesture 交付對象在 QGestureEvent 被發送給目標對象並審查它包含的信息。

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();
    }
}
					

這裏,我們審查用戶輕掃 Widget 的方嚮並相應修改其內容。

創建自己的手勢識彆器

添加支持新手勢涉及創建並注冊新手勢識彆器。從屬手勢識彆過程,還可能涉及創建新手勢對象。

要創建新識彆器,需要子類化 QGestureRecognizer 以創建自定義識彆器類。有 1 個虛函數必須重實現,和其它 2 個可以按要求重實現。

過濾輸入事件

The recognize() 函數必須被重實現。此函數處理並過濾用於目標對象的傳入輸入事件,和確定它們是否對應識彆器正查找的手勢。

盡管手勢識彆邏輯是在此函數中實現的,可能使用狀態機基於 Qt::GestureState 枚舉,可以將識彆過程狀態的有關持久信息存儲在 QGesture 供給對象。

您的 recognize() 函數必須返迴值為 QGestureRecognizer::Result 指示給定手勢和目標對象的識彆狀態。這確定是否有將手勢事件交付給目標對象。

自定義手勢

若要選擇錶示手勢通過自定義 QGesture 子類,將需要重實現 create() 函數以構造手勢類實例,而不是標準 QGesture 實例。另外,可能想要使用標準 QGesture 實例,但要對它們添加額外動態特性以錶達想要處理手勢的特定細節。

重置手勢

若取消手勢時使用需要重置 (或其它特殊處理) 的自定義手勢對象,需要重實現 reset() 函數以履行這些特殊任務。

注意, QGesture 對象隻創建一次對於目標對象和手勢類型的每個組閤,且會重用它們每當用戶試圖對目標對象履行相同手勢類型時。因此,會很有用重實現 reset() 函數以清理先前識彆的手勢,在每次嘗試後。

使用新的手勢識彆器

要使用手勢識彆器,構建實例化的 QGestureRecognizer 子類,並將它注冊到應用程序采用 QGestureRecognizer::registerRecognizer ()。可以移除給定類型的手勢識彆器采用 QGestureRecognizer::unregisterRecognizer ().

延伸閱讀

The 圖像手勢範例 展示如何在簡單圖像查看器應用程序中為 Widget 啓用手勢。

Qt Quick 中的手勢

Qt Quick 沒有一般全局手勢識彆器;相反,各個組件可以按自己的方式響應觸摸事件。例如 PinchArea 處理 2 指手勢, Flickable 按單指輕彈內容,和 MultiPointTouchArea 可以處理任意數量的接觸點並允許應用程序開發者編寫自定義手勢識彆代碼。