Registering custom gesture recognizer and handling the returned gesture type



  • When creating a custom gesture recognizer this has to be registered. As the documentation states

    The application takes ownership of the recognizer and returns the gesture type ID associated with it. For gesture recognizers which handle custom QGesture objects (i.e., those which return Qt::CustomGesture in a QGesture::gestureType() function) the return value is a generated gesture ID with the Qt::CustomGesture flag set.

    This means that it is completely legit to do (for example inside the widget's constructor):

    Widget::Widget(QWidget* parent)
    {
        // ...
        CustomGestureRecognizer* customRecognizer = new CustomGestureRecognizer();
        QGestureRecognizer::registerRecognizer(customRecognizer);
    }
    

    Note that due to the way registration of recognizers works we are required to allocate the recognizer dynamically! Otherwise you will experience a nasty segfault. :)

    In order to handle the specific gesture type in the even handler of our widget we are required to store it somewhere. Since Qt::GestureType QGestureRecognizer::registerRecognizer(QGestureRecognizer *recognizer) is a static method and due to the quote from above there are two plausible (omho) options here:

    • Store the registered type as a class member variable (or push it onto a vector, list etc. but again the container that stores it has to be alive throughout the lifecycle of the widget so that you can call upon it when receiving events) that is part of your custom QWidget

    • Store a pointer to the recognizer as a class member of your custom QWidgeT and also store the registered type inside the recognizer itself as a class member:

      class CustomGestureRecognizer : public QGestureRecognizer
      {
      public:
          CustomGestureRecognizer();
          QGestureRecognizer::Result recognize(QGesture* aState, QObject* aWatched, QEvent* aEvent);
          void setRegisteredGestureType(Qt::GestureType aGestureType);
          Qt::GestureType getRegisterdGestureType();
      private:
          Qt::GestureType registeredGestureType;
      };
      

    With the code above we can do:

    bool Widget::event(QEvent* event)
    {
        if (event->type() == QEvent::Gesture) {
            bool res = gestureEvent(static_cast<QGestureEvent*>(event));
            return res;
        }
    
        return QWidget::event(event);
    }
    
    bool Widget::gestureEvent(QGestureEvent* gestureEvent)
    {
        QGesture* gesture = Q_NULLPTR;
    
        if ((gesture = gestureEvent->gesture(Qt::SwipeGesture))) {
            bool res = gestureSwipeTriggered(static_cast<QSwipeGesture*>(gesture));
            return res;
        }
        else if ((gesture = gestureEvent->gesture(Qt::TapGesture))) {
            bool res = gestureTapTriggered(static_cast<QTapGesture*>(gesture));
            return res;
        }
        // Handle the CustomGesture type here
        else if ((gesture = gestureEvent->gesture(this->customGestureRecognizer->getRegisteredGestureType()))) {
            bool res = gestureCustomTriggered(gesture);
            return res;
        }
    
        return false;
    }
    
    bool Widget::gestureCustomTriggered(QGesture* aCustomGesture)
    {
        // Do something with recognized custom gesture
        return true;
    }
    

    We are in fact required to use the registered type since Qt::CustomGesture (equal to 256) is just as (also what the documentation states) a flag that is a base which, combined with an internally generated offset (256+1, 256+2, 256+3 ...), generates the actual gesture type for the custom gesture.

    Frankly I find storing everything together much better due to the fact that all the information related to the recognition will be part of the same object. The documentation doesn't mention what happens with the allocated instance of the recognizer upon unregistering it. I tried to call QGestureRecognizer::unregisterRecognizer(<registered_custom_gesture_type>) and all my application did was to stop processing the given custom gesture. It did not crash which would mean that the allocated instance is still available after unregistering it.

    I have to wonder why storing the registered custom gesture type inside the recognizer is not done but instead we have to handle the storing on our own especially because of that the application takes ownership of the recognizer and returns the gesture type ID associated with it thing. The documentation also doesn't mention ANYTHING about reusing custom gesture types. For example if we unregister our CustomGestureRecognizer what happens with it? Is the registered custom gesture type free to be taken by a different recognizer that is registered afterwards? Frankly the last wouldn't make much sense since processing a gesture event in the application needs to be something very specific and suddenly having a different gesture do what a previously registered other gesture has done would be confusing to the user. All this is (at least I couldn't find anything) undocumented behaviour and I would like to know how we are supposed to generally do all that I described above.

    Thanks in advance!


  • Qt Champions 2016

    @Red-Baron said in Registering custom gesture recognizer and handling the returned gesture type:

    The documentation doesn't mention what happens with the allocated instance of the recognizer upon unregistering it. I tried to call QGestureRecognizer::unregisterRecognizer(<registered_custom_gesture_type>) and all my application did was to stop processing the given custom gesture. It did not crash which would mean that the allocated instance is still available after unregistering it.

    See below.

    For example if we unregister our CustomGestureRecognizer what happens with it?

    Since you own the recognizer (as you sourced from the docs) it's your own responsibility to clean it up.

    I have to wonder why storing the registered custom gesture type inside the recognizer is not done but instead we have to handle the storing on our own especially because of that the application takes ownership of the recognizer and returns the gesture type ID associated with it thing.

    See below.

    Is the registered custom gesture type free to be taken by a different recognizer that is registered afterwards?

    This is implementation detail (especially if not documented). Just save the integers you get for the different recognizers as you'd do if you were registering custom event and their event types.

    Frankly the last wouldn't make much sense since processing a gesture event in the application needs to be something very specific and suddenly having a different gesture do what a previously registered other gesture has done would be confusing to the user.

    It's just an integer and there's no problem if it changes when unregister-registering.

    Kind regards.



  • Thanks for the detailed reply. I'm asking about the memory management since I have tried a couple of months ago to delete a recognizer that was registered inside the destructor of my widget and I got segmentation fault. Then I started digging in the source code of Qt and found what the "takes ownership" means - the gesture manager releases the memory and if you do that too (for a registered recognizer) you get a double free which is obviously not allowed. So basically unregistering the recognizer removes the ownership by the gesture manager and indeed I am the one who is responsible to clean up. Thanks again for the help!

    PS: Weird, I don't have "Mark as solved" in my "Topic tools". I've added "[Solved]" to the thread's name. Hope that a moderator sees it and marks it for me. Strange...


  • Qt Champions 2016

    Yes. Taking ownership literally means to be responsible to free the object/resources. It's used quite often in the docs in border cases - where the user would create an object and pass it to Qt, or vice versa.

    PS: Weird, I don't have "Mark as solved" in my "Topic tools". I've added "[Solved]" to the thread's name. Hope that a moderator sees it and marks it for me. Strange...

    Your topic isn't a "question topic", that's why you don't see it. I'll convert and mark it.



  • @kshegunov Thanks. XD



  • @Red-Baron @kshegunov
    Hello guys.
    im trying to creat a custom Finger sweep with only 1 touch point ,well i created the class it self .now im having problem with registering it to my custom widget:

    // Handle the CustomGesture type here
        else if ((gesture = gestureEvent->gesture(this->customGestureRecognizer->getRegisteredGestureType()))) {
            bool res = gestureCustomTriggered(gesture);
            return res;
        }
    

    in this part of your code , this wont indicate any customGestureRecognizer (which in my case the name is FingerSwipeGestureRecognizer ).
    here is the constructor of my widget :

    galary::galary(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::galary)
    {
        ui->setupUi(this);
    
        setAttribute(Qt::WA_AcceptTouchEvents);
        FingerSwipeGestureRecognizer* customRecognizer = new FingerSwipeGestureRecognizer;
        QGestureRecognizer::registerRecognizer(customRecognizer);
        grabGesture(Qt::CustomGesture);
    
    }
    

    custom gesture Recognizer in header file:

    class FingerSwipeGestureRecognizer : public QGestureRecognizer
     {
     public:
         FingerSwipeGestureRecognizer();
    
         QGesture *create(QObject *target);
         QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event);
         void reset(QGesture *state);
         void setRegisteredGestureType(Qt::GestureType aGestureType);
             Qt::GestureType getRegisterdGestureType();
         private:
             Qt::GestureType registeredGestureType;
     };
    
    

    is there anything that im missing ?



  • QGestureRecognizer::registerRecognizer(customRecognizer); returns the type that you need to store somewhere (in my case I stored it inside my recognizer to keep things in the same spot). Use the returned type as argument for setRegisteredGestureType(...) and you are good to go.



  • @md2012 Also use it for the grabGesture(...) too. Qt::CustomGesture is something different. All custom gestures have the Qt::CustomGesture flag set unlike the predefine swipe, tap etc. which have their own (but part of the same enumeration).


Log in to reply
 

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