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
?
Because QTapAndHoldGesture
gesture also requires a "Tap", it is expected to receive both:
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 (Disclaimer: 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 love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With