Sunday, October 3, 2010

Detecting Swipe gesture in Qt

In continuation of my previous post of long press gesture in Qt, I created another simple gesture class to detect swipe gesture.

In my implementation, I am storing initial coordinate on mouse press event and comparing initial coordinate with coordinate on mouse release event.In this code I have not considered speed of swipe but we can easily measure speed of swipe by measuring time difference between two event.

myswipegesture.h file
#ifndef MYSWIPEGESTURE_H
#define MYSWIPEGESTURE_H

#include <QObject>
#include <QPoint>

class MySwipeGesture : public QObject
{
    Q_OBJECT
public:
    explicit MySwipeGesture(QObject *parent = 0);
    void handleEvent( QEvent *event);
public:
    enum SwipeDirection {
        Left = 0,
        Right,
        Up,
        Down
    };
signals:
    void handleSwipe( MySwipeGesture::SwipeDirection direction );
private:
    QPoint _startPoint;
    QPoint _endPoint;
};
#endif // MYSWIPEGESTURE_H
myswipegesture.cpp file
#include "myswipegesture.h"
#include <QEvent>
#include <QMouseEvent>

MySwipeGesture::MySwipeGesture(QObject *parent)
    :QObject(parent),_startPoint(0,0),_endPoint(0,0)
{}

void MySwipeGesture::handleEvent( QEvent *event)
{
    if( event->type() == QEvent::MouseButtonPress ) {
    QMouseEvent* mouseEvent = static_cast<QMouseEvent*> (event);
        _startPoint = mouseEvent->pos();
    } else if( event->type() == QEvent::MouseButtonRelease ) {
    QMouseEvent* mouseEvent = static_cast<QMouseEvent*> (event);
        _endPoint = mouseEvent->pos();

        //process distance and direction
        int xDiff = _startPoint.x() - _endPoint.x();
        int yDiff = _startPoint.y() - _endPoint.y();
        if( qAbs(xDiff) > qAbs(yDiff) ) {
            // horizontal swipe detected, now find direction
            if( _startPoint.x() > _endPoint.x() ) {
                emit handleSwipe( Left);
            } else {
                emit handleSwipe( Right);
            }
        } else {
            // vertical swipe detected, now find direction
            if( _startPoint.y() > _endPoint.y() ) {
                emit handleSwipe( Up);
            } else {
                emit handleSwipe( Down);
            }
        }
    } else if( event->type() == QEvent::MouseMove ) {
        //ignore event
    }
}
Some test code.
#include "myswipegesture.h"

TestWidget::TestWidget(QWidget *parent) : QWidget(parent)
{
    _swipeGesture = new MySwipeGesture(this);
    connect(_swipeGesture,SIGNAL(handleSwipe(MySwipeGesture::SwipeDirection)),this,SLOT(swipe(MySwipeGesture::SwipeDirection)));
}

bool TestWidget::event(QEvent *event)
{
    _swipeGesture->handleEvent(event);
    return QWidget::event(event);
}

void TestWidget::swipe(MySwipeGesture::SwipeDirection direction)
{
    qDebug() << "swipe" << direction;
}
Hope this helps.

24 comments:

  1. Wow, looks like a nice piece of code - now to go and learn c++/QT to see how to implement it!!!

    Tis just the test code part that i can't get compiling :P
    (me @ mywebsiteaddy .com)

    ReplyDelete
  2. Greate piece of code, thanks!

    ReplyDelete
  3. Thanks a lot.. It really helped me!

    ReplyDelete
  4. You are welcome :) I m glad that it helped you.

    ReplyDelete
  5. Hey Kunal !

    Thanks ! This was just what I was looking for !

    I am implementing my UI in QML and tried many things with GestureArea, MouseArea etc.

    Can u show an example how to link this with QML, I mean, its like this :

    If swipe detected, do this in QML

    And, is this only for horizontal or vertical swipe, can we get the angle ?

    Thanks !!!

    ReplyDelete
  6. For angle, you can get slop of line ( start point and end point) and from slop you can get angle.

    Same thing can be implemented in QML using MouseArea and handiling onPressed and onReleased event. I will try to put some example here.

    ReplyDelete
  7. Hey Kunal!
    I have 2 windows. One is a main window and second a new window. I want to go to new window from main window and vice versa by scrolling(using mouse on simulator and touch on device) and not by any pushbutton or anything else.

    Could you help something in this case?
    Thanks in advance.

    ReplyDelete
  8. I guess, you already know that how to switch window, i you can use QStackedWidget or for QML I have a blog post to swich QML screen.

    Now you need is to detect swipe direction and activate appropriate window.

    ReplyDelete
  9. can you provide some code with detecting swipe direction ? i really have no idea how to implement this thing.

    ReplyDelete
  10. this post shows, how to detect the swipe as well as its direction, for example handleSwipesignal indicate swipe in right direction - >emit handleSwipe( Right);

    Please check the code in post.

    ReplyDelete
  11. what is " some test code" ?

    ReplyDelete
  12. test code, which test my implementation

    ReplyDelete
  13. where should i write this code? what name?

    ReplyDelete
  14. your widget class, where you want to detect swipe gesture

    ReplyDelete
  15. \test\main.cpp:12: error: 'class MySwipeGesture' has no member named 'show'. I got this error. Can you tell something about this? I kept your test code as testwidget.cpp

    ReplyDelete
  16. Even if i dont include your test code, the error remains the same

    ReplyDelete
    Replies
    1. I think you should go through some nice widget programming tutorial first, once you understand basic widget programming with Qt, then you will easily follow this post.

      Delete
  17. Hi Kunal,
    Will it be possible for you to show the same example in QML,
    I have been trying swiping left and right among different pages of my application using QML logic, but the swipe is coming terrible :)

    I have been using the following logic to do that ,

    onTouch: {
    if (event.isDown()) {
    downX = event.windowX;
    downY = event.windowY;
    } else if (event.isUp()) {
    var yDiff = downY - event.windowY;

    // take absolute value of yDiff
    if (yDiff < 0) yDiff = -1 * yDiff;

    // I check if the minimum y movement is less than 200. Don't want to move left or right if
    // the user is actually want to move up or down.
    if ((yDiff) < 200) {
    if ((downX - event.windowX) > 320) {
    console.debug("appsList.qml onTouch... move left");
    _app.LoadWebLinkPage();

    } else if ((event.windowX - downX) > 320) {
    console.debug("appsList.qml onTouch... move right");
    _app.LoadFavoritePage();
    }
    }
    }
    }

    Can you suggest some better approach

    ReplyDelete
    Replies
    1. Hi, I will try to post same sample code for QML as well.

      Delete
  18. Thanks very much Kunal , I will wait for your sample code !!

    ReplyDelete
    Replies
    1. Hello, I added code here, http://kunalmaemo.blogspot.kr/2014/04/creating-custom-swipe-handler-in-qml.html

      Delete
  19. I like it!!
    Helped me a lot to move around my stacked widget items on android :-)

    I will credit you in my source code

    ReplyDelete