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 custom QGesture-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 and QGesture(if the recognize() 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 a QGesture. 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 what recognize() 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 add grabGesture(fftType) in the label's constructor. Now I can capture data and evaluate it in a state-wise fashion (for example storing event.pos() in a list and then going through that list to see if a gesture might have been caught or not).


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.