Wednesday, May 30, 2018

ignore QTapGesture after QTapAndHoldGesture

Leave a Comment

I want to get QTapAndHoldGesture and QTapGesture in my widget and do different thing as reaction on these gestures. So I override QWidget::event method and add such code:

 bool event(QEvent *event) override {     if (event->type() == QEvent::Gesture) {       auto g_event = static_cast<QGestureEvent *>(event);       qDebug() << "GestureEvent BEGIN: gestures " << g_event->gestures().size() << ", active: " << g_event->activeGestures();       if (auto g = qobject_cast<QTapGesture *>(g_event->gesture(Qt::TapGesture))) {         g_event->accept(g);         return true;       }       if (auto g = qobject_cast<QTapAndHoldGesture *>(g_event->gesture(Qt::TapAndHoldGesture))) {         if (g->state() == Qt::GestureFinished) {                 qDebug("FINISHED!!!");                 g->setGestureCancelPolicy(QGesture::CancelAllInContext);         }         g_event->accept(g);         return true;       } 

The problem is that I get not wanted QTapGesture at the end of QTapAndHoldGesture.

It looks like this:

GestureEvent BEGIN: gestures  1 , active:  (QTapGesture(state=GestureStarted,hotSpot=773.396,492.884,position=773.396,492.884)) GestureEvent BEGIN: gestures  1 , active:  (QTapGesture(state=GestureUpdated,hotSpot=773.396,492.884,position=773.396,492.884)) mouse event x  773 , y  493 GestureEvent BEGIN: gestures  1 , active:  (QTapGesture(state=GestureUpdated,hotSpot=773.396,492.884,position=773.396,492.884)) ... GestureEvent BEGIN: gestures  1 , active:  (QTapGesture(state=GestureUpdated,hotSpot=773.396,492.884,position=773.396,492.884)) GestureEvent BEGIN: gestures  1 , active:  (QTapAndHoldGesture(state=GestureStarted,hotSpot=773,493,position=773,493,timeout=700)) GestureEvent BEGIN: gestures  1 , active:  (QTapAndHoldGesture(state=GestureFinished,hotSpot=773,493,position=773,493,timeout=700)) FINISHED!!! GestureEvent BEGIN: gestures  1 , active:  (QTapGesture(state=GestureUpdated,hotSpot=773.396,492.884,position=773.396,492.884)) GestureEvent BEGIN: gestures  1 , active:  (QTapGesture(state=GestureUpdated,hotSpot=773.396,492.884,position=773.396,492.884)) GestureEvent BEGIN: gestures  1 , active:  (QTapGesture(state=GestureFinished,hotSpot=773.396,492.884,position=773.396,492.884)) 

As you see at start I got QTapGesture in started state, then QTapGesture in updated state, after that QTapAndHoldGesture and after that QTabGesture finished.

I need some way to ignore it. But I don't see how without re-implementing of gesture framework: collect position and time of event and filter events based on this information. Because of I receive gestures one by one and can not connect QTapGesture and QTapAndHoldGesture.

So is it possible to ignore QTapGesture after QTapAndHoldGesture without collecting information about position and time of QGestureEvent?

1 Answers

Answers 1

Because QTapAndHoldGesture gesture also requires a "Tap", it is expected to receive both:

  • QTapAndHoldGesture first, when the users holds for a certain time (end of a timer)
  • QTapGesture then, when the user releases the touch

Because they will always be received in that order, you can use that fact, to filter or cancel the QTapGesture which will be started, but not finished, when you receive QTapAndHoldGesture is validated (i.e. finished).

No need for time or position information, if you are managing a single touch point (Disclamer: The following is untested).

bool MyClass::event(QEvent *event) override {     // QPointer in case we receive partial events. Should remove "isNull()" keys at some point.     static QMap<QPointer<QTapGesture*>, bool> tapGestures;     if (event->type() != QEvent::Gesture)         return QQuickItem::event(event);      auto g_event = static_cast<QGestureEvent *>(event);     if (auto g = qobject_cast<QTapGesture *>(g_event->gesture(Qt::TapGesture))) {         // A TapAndHold was triggered during that tap... let's ignore it         if (tapGestures.value(g))             g_event->ignore(g); // Or handle as you like          if (g->state() == Qt::GestureFinished || g->state() == Qt::GestureCancelled)             tapGestures.remove(g);         else if (!tapGestures.contains(g))             tapGestures.insert(g, false);          g_event->accept(g);         return true;     }      if (auto g = qobject_cast<QTapAndHoldGesture *>(g_event->gesture(Qt::TapAndHoldGesture))) {         // Probably not needed if the gesture handle doesn't conflict with another component         //if (g->state() == Qt::GestureFinished)         //    g->setGestureCancelPolicy(QGesture::CancelAllInContext);          // Mark all QTapGesture in progress to be ignored         for (auto it = tapGestures.begin(); it != tapGestures.end(); ++it)             it.value() = true;          g_event->accept(g);         return true;     } } 

All gestures are available in QGestureManager class, so there may be a way to access it.

There is also the GestureOverride event type, but I believe that in your case it will not be triggered.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment