Custom gestures - are there any examples out there?
-
See code at the end
I'm currently working with the Microchip GestiC technology (using the 3DTouchPad). I intend to add gesture control to my application. The device supports both 2D and 3D gestures and even has a dedicated port for outputting gestures in real time (it has a built-in Hidden Markov model for the recognition loaded in the flash memory of the controller). I've decided to go with the
QGesture
API since it should provide easy and seamless integration with whatever Qt-based application I decide to develop. My current goal is to create a mapper from the output of the gesture port or the raw signals to both standard and customQGesture
-s.I've already looked into the ImageGestures example however I seem to be unable to find any full examples of how to create custom gestures. The part about how to implement a custom
QGestureRecognizer
andQGesture
(if therecognize()
of the custom recognizer is implemented) in the documentation is as lacking as one can only imagine:-
Custom Gestures
If you choose to represent a gesture by a custom QGesture subclass, you will need to reimplement the create() function to construct instances of your gesture class instead of standard QGesture instances. Alternatively, you may want to use standard QGesture instances, but add additional dynamic properties to them to express specific details of the gesture you want to handle.
-
Resetting Gestures
If you use custom gesture objects that need to be reset or otherwise specially handled when a gesture is canceled, you need to reimplement the reset() function to perform these special tasks.
Note that QGesture objects are only created once for each combination of target object and gesture type, and they might be reused every time the user attempts to perform the same gesture type on the target object. As a result, it can be useful to reimplement the reset() function to clean up after each previous attempt at recognizing a gesture.
-
Using a New Gesture Recognizer
To use a gesture recognizer, construct an instance of your QGestureRecognizer subclass, and register it with the application with QGestureRecognizer::registerRecognizer(). A recognizer for a given type of gesture can be removed with QGestureRecognizer::unregisterRecognizer().
I've already understood that however I have no idea what to put inside the
recognize()
or how to properly configure aQGesture
. I even looked into the sources but there is just too few information (at least for me) to produce working code. In particular I'm very interested in the state based gesture recognition (which to my knowledge is whatrecognize()
is meant to do) that is capture multiple event and decide whether it's a gesture or not. For example:- Move finger up - not a gesture
- Then (without interruption in the movement) move finger to the left - still not a gesture
- Finally (again - no interruption in the movement) move finger down - gesture recognized!
Has anyone done a completely new gesture (like one that is not included into the standard ones such as pinch, pan, swipe etc.)? I would really appreciate if someone provides a simple example how to do that. I'll also try to provide some code tomorrow so that should also be a start from somewhere.
CODE
I've read a Qt DevDays 2009 presentation where the guy presented a custom four finger tap gesture. The example however is incomplete and with the current version of Qt 5.7 chock full with errors. I've tried to complement the code to the best of my knowledge so at least it compiles and runs without issue. Needless to say the gesture doesn't work.
main.cpp
#include "gesturewidget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); GestureWidget w; w.show(); return a.exec(); }
gesturewidget.h
#include <QWidget> #include "gesturelabel.h" namespace Ui { class GestureWidget; } class GestureWidget : public QWidget { Q_OBJECT public: explicit GestureWidget(QWidget *parent = 0); ~GestureWidget(); private: Ui::GestureWidget *ui; GestureLabel *label; };
gesturewidget.cpp
#include "gesturewidget.h" #include "ui_gesturewidget.h" GestureWidget::GestureWidget(QWidget *parent) : QWidget(parent), ui(new Ui::GestureWidget) { ui->setupUi(this); setAttribute(Qt::WA_AcceptTouchEvents); label = new GestureLabel(this); label->setText("Hello!"); label->grabGesture(label->getFftType()); ui->verticalLayout->addWidget(label); } GestureWidget::~GestureWidget() { delete ui; }
gesturelabel.h
#include <QtWidgets> #include "fourfingertap.h" class GestureLabel : public QLabel { Q_OBJECT public: explicit GestureLabel(QWidget *parent = 0); Qt::GestureType getFftType(); signals: public slots: private: FourFingerTapGesture *fftRecognizer; Qt::GestureType fftType; virtual void gestureEvent(QGestureEvent *event); };
gesturelabel.cpp
#include "gesturelabel.h" #include <iostream> using std::cout; using std::endl; GestureLabel::GestureLabel(QWidget *parent) : QLabel(parent) { setAttribute(Qt::WA_AcceptTouchEvents); fftRecognizer = new FourFingerTapGesture(); fftType = QGestureRecognizer::registerRecognizer(fftRecognizer); } Qt::GestureType GestureLabel::getFftType() { return fftType; } void GestureLabel::gestureEvent(QGestureEvent *event) { cout << "Gesture event captured" << endl; if(QGesture *g = event->gesture(fftType)) { setText(g->property("foo").toString()); event->accept(g); } }
fourfingertap.h
#include <QGesture> #include <QGestureRecognizer> class FFTGesture : public QGesture { Q_PROPERTY(QString foo READ getFoo WRITE setFoo) public: FFTGesture(QObject *parent = 0); QString getFoo(); void setFoo(QString foo); private: QString foo; }; class FourFingerTapGesture : public QGestureRecognizer { public: FourFingerTapGesture(); private: virtual QGesture *create(QObject *target); virtual Result recognize(QGesture *state, QObject *watched, QEvent *event); };
fourfingertap.cpp
#include "fourfingertap.h" #include <QTouchEvent> FourFingerTapGesture::FourFingerTapGesture() : QGestureRecognizer() { } QGesture *FourFingerTapGesture::create(QObject *target) { return static_cast<QGesture *>(new FFTGesture()); } QGestureRecognizer::Result FourFingerTapGesture::recognize(QGesture *state, QObject *watched, QEvent *event) { if (event->type() == QEvent::TouchUpdate) { if (static_cast<QTouchEvent *>(event)->touchPoints().size() == 4) { state->setProperty("foo", QLatin1String("GESTURES")); return FinishGesture; } } return Ignore; } FFTGesture::FFTGesture(QObject *parent) : QGesture(parent), foo("FFT_GESTURE") { } QString FFTGesture::getFoo() { return foo; } void FFTGesture::setFoo(QString _foo) { foo = _foo; }
Regards,
RB -
-
facepalm I missed to overriding of the
event(QEvent *event)
inside my special label AND I also missed to subscribe the label to the gesture that is I had to addgrabGesture(fftType)
in the label's constructor. Now I can capture data and evaluate it in a state-wise fashion (for example storingevent.pos()
in a list and then going through that list to see if a gesture might have been caught or not).