Qt最新的版本4.7中有五個gesture,分別是QPanGesture, QPinchGesture, QSwipeGesture, QTapAndHoldGesture, and QTapGesture, 前三個比較常用,但用過的人仍然很少,很多人人對這個gesture意思感覺也陌生,更不用說對說出他們之間的區別了。這裏我先解釋一下: Pan Gesture就是指一個手指在屏幕上滑動,當滑動距離超過一定大小時就產生了一個Pan Gesture的事件了,如下圖所示:
Pinch Gesture就是兩指放在屏幕上,靠近或者遠離,就像捏東西一樣,如下圖所示:
Swipe Gesture就是一個手指在屏幕上沿着一個固定的方向滑動,滑動一段距離時就產生了一個Swipe Gesture的事件,如下圖所示:
QTapAndHoldGesture和QTapGesture比較簡單這裏我就偷個懶不說了,哈哈。 Gesture是個手勢,但是個組合拳,過濾Gesture是消耗很大的,一般來說它要過濾好幾個事件,要與你要截獲的Gesture對比,看有沒有可能是你要的那個手勢,如果所有事件都會做很多無用功,因此只有真的我們需要截獲那個gesture時纔會讓系統幫我們這麼做。
我比較喜歡看源碼說事,就來看看 每個gesture都有對應的gesture recognizer(手勢識別類)來識別這個gesture,比如QPanGesture,它就有QPanGestureRecognizer。可有了gesture recognizer,系統就認識你這個gesture了嗎?不是,你還要將你的gesture recognizer註冊到QGestureManager中,而QGestureManager則統一管理所有的gesture recognizer,系統只要通過QGestureManager就可以來識別相應的gesture。讓我們來看看QGestureManager的構造函數源碼:
- QGestureManager::QGestureManager(QObject *parent)
- : QObject(parent), state(NotGesture), m_lastCustomGestureId(0)
- {
- qRegisterMetaType<Qt::GestureState>();
-
- #if defined(Q_WS_MAC)
- registerGestureRecognizer(new QMacSwipeGestureRecognizer);
- registerGestureRecognizer(new QMacPinchGestureRecognizer);
- #if defined(QT_MAC_USE_COCOA)
- registerGestureRecognizer(new QMacPanGestureRecognizer);
- #endif
- #else
- registerGestureRecognizer(new QPanGestureRecognizer);
- registerGestureRecognizer(new QPinchGestureRecognizer);
- registerGestureRecognizer(new QSwipeGestureRecognizer);
- registerGestureRecognizer(new QTapGestureRecognizer);
- #endif
- #if defined(Q_OS_WIN)
- #if !defined(QT_NO_NATIVE_GESTURES)
- if (QApplicationPrivate::HasTouchSupport)
- registerGestureRecognizer(new QWinNativePanGestureRecognizer);
- #endif
- #else
- registerGestureRecognizer(new QTapAndHoldGestureRecognizer);
- #endif
- }
複製代碼
上面的代碼很簡單這裏我只簡單說說,registerGestureRecognizer就是用來註冊gesture recognizer的,剛開始說的五個gesture在這裏都註冊了。 我們再了看看registerGestureRecognizer函數:
- Qt::GestureType QGestureManager::registerGestureRecognizer(QGestureRecognizer *recognizer)
- {
- //這裏也用你的recognizer創建一個你的gesture實例,如果沒有創建成功就
- //返回Qt::GestureType(0),表示註冊失敗
- QGesture *dummy = recognizer->create(0);
- if (!dummy) {
- qWarning("QGestureManager::registerGestureRecognizer: "
- "the recognizer fails to create a gesture object, skipping registration.");
- return Qt::GestureType(0);
- }
-
- //Code A
- //這裏如果發現你的gestureType是CustomGesture則會
- //返回Qt::GestureType(Qt::CustomGesture + m_lastCustomGestureId)
- //即在Qt::CustomGesture基礎上加一個數字,如果是註冊第一個的自定義的gesture,
- //這裏的m_lastCustomGestureId就是1,再註冊就加2,以此類推
- //這裏對我們理解自定義gesture很有幫助:)
- Qt::GestureType type = dummy->gestureType();
- if (type == Qt::CustomGesture) {
- // generate a new custom gesture id
- ++m_lastCustomGestureId;
- type = Qt::GestureType(Qt::CustomGesture + m_lastCustomGestureId);
- }
- m_recognizers.insertMulti(type, recognizer);
- delete dummy;
- return type;
- }
複製代碼
上面代碼中註釋的應該比較全,這裏我只就Code A部分說一下,如果我自定義一個gesture時,無需管它的gesture類型,也不用重新實現它的gestureType方法,默認的就是Qt::CustomGesture,這裏的你的gesture類型id你可以通過調用QGestureRecognizer::registerRecognizer方法的返回值來獲得,也可以根據上面的代碼在Qt::CustomGesture基礎上加上相應的數字來得到。
說完這些,讓我們來看看有關gesture的事件傳遞的過程: 當你通過調用QWidget::grabGesture來截獲相應的gesture手勢時 如果你想截獲某個手勢,你需要調用QWidget::grabGesture方法來截獲相應的手勢類型,我們來看看QWidget::grabGesture方法源碼:
- void QWidget::grabGesture(Qt::GestureType gesture, Qt::GestureFlags flags)
- {
- Q_D(QWidget);
- //這裏先向gestureContext,即手勢上下文,插入這個gesture類型
- //gestureContext是屬於這個widget的QWidgetPrivate的,可見這裏的截獲事件緊限於這個widget
- d->gestureContext.insert(gesture, flags);
- // 創建gesture manager,這裏用的是單例模式,哈哈
- (void)QGestureManager::instance();
- }
複製代碼
這樣之後,當事件最終通過經過QApplication::notify方法處理時,如果發現接受事件的widet有截獲gesture時,就會將事件叫給gesture manager來過濾。 整個過程事件傳遞如下圖所示:
|