Sunday, September 26, 2010

Detecting Tap And Hold (Long Press) event in Qt

Recently while working on Qt project I required to recognize Tap and Hold (Long Press) gesture. Qt introduced new gesture handler library in 4.6 but some how it was not working on my machine and I needed to create my own solution. I already have created one custom solution for detecting Tap and Hold for iOS and I tried to port same thing to Qt as well.

Following is my code to detect Tap and Hold for Qt. In code I am starting timer on mouse press event, if timer expire then we have Tap and Hold event. If user release mouse while timer is still active then Tap and Hold is canceled.
#ifndef MYTAPANDHOLDGESTURE_H
#define MYTAPANDHOLDGESTURE_H

#include <QObject>

class QTimer;

class MyTapAndHoldGesture: public QObject
{
    Q_OBJECT
public:
    MyTapAndHoldGesture( QObject *parent = 0 );
    void handleEvent( QEvent *event);

signals:
    void handleTapAndHold();

private slots:
    void timeout();

private:
    QTimer* _timer;
};

#endif // MYTAPANDHOLDGESTURE_H

#include "mytapandholdgesture.h"

#include <QMouseEvent>
#include <QTimer>

MyTapAndHoldGesture::MyTapAndHoldGesture( QObject *parent )
{
    _timer = new QTimer(this);
    connect(_timer,SIGNAL(timeout()),this,SLOT(timeout()));
}

void MyTapAndHoldGesture::handleEvent( QEvent *event)
{
    if( event->type() == QEvent::MouseButtonPress ) {
        _timer->start( 1000 );
    } else if( event->type() == QEvent::MouseButtonRelease ) {
        if( _timer->isActive() ) {
            // tap and hold canceled
            _timer->stop();
        }
    } else if( event->type() == QEvent::MouseMove ) {
        // tap and hold canceled
        _timer->stop();
    }
}

void MyTapAndHoldGesture::timeout()
{
    emit handleTapAndHold();
    _timer->stop();
}

Widget code for testing.
#ifndef TESTWIDGET_H
#define TESTWIDGET_H

#include <QWidget>

class MyTapAndHoldGesture;

class TestWidget : public QWidget
{
    Q_OBJECT
public:
    TestWidget(QWidget *parent = 0);

private:
    bool event(QEvent *event);

private slots:
    void tapAndHold();

private:
    MyTapAndHoldGesture* _gestureHandler;
};

#endif // TESTWIDGET_H

#include "testwidget.h"
#include <QDebug>
#include "mytapandholdgesture.h"

TestWidget::TestWidget(QWidget *parent) :
    QWidget(parent)
{
    _gestureHandler = new MyTapAndHoldGesture(this);
    connect(_gestureHandler,SIGNAL(handleTapAndHold()),
    this,SLOT(tapAndHold()));
}

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

void TestWidget::tapAndHold()
{
    qDebug() << "tapAndHold";
}

Wednesday, September 15, 2010

Simple priority queue with Qt

Recently in one of my Qt project I required to use priority queue and found that Qt framework dose not provide such container. Then I decided to write one my self.

Following is simple version of my actual implementation.

In code Queue class implement simple priority queue. Internally I am using QQueue as storage and created one helper structure which holds data and its priority. Actual work is done inside enqueue method, which check priority of item being inserted with other stored items and insert item at appropriate index.
#ifndef QUEUE_H
#define QUEUE_H

#include <QQueue>
#include <QDebug>

enum Priority {
    Normal = 0,
    High = 1
};

template<class T>
class Queue
{
public:

    Queue()
    {}

    void enqueue(Priority priority,T value)
    {
        Item<T> item(priority,value);
        for(int i = 0 ; i < _queue.count() ; ++i ) {
            const Item<T>& otherItem = _queue[i];
            if( priority > otherItem._priority )  {
                _queue.insert(i,item);
                return;
            }
        }
        _queue.append(item);
    }

    T dequeue()
    {
        const Item<T>& item = _queue.dequeue();
        return item._value;
    }

    int count()
    {
        return _queue.count();
    }

private:

    template<class C>
    struct Item
    {
        Priority _priority;
        C _value;

        Item(Priority priority, C value)
        {
            _priority = priority;
            _value = value;
        }
    };

    QQueue< Item<T > > _queue;

};

#endif // QUEUE_H

Some basic test code.
{
    //testing with int as value
    Queue<int> q;
    q.enqueue(High,1);
    q.enqueue(Normal,2);
    q.enqueue(High,3);
    q.enqueue(Normal,5);
    q.enqueue(Normal,6);
    q.enqueue(High,4);

    //output should be 1,3,4,2,5,6
    while( q.count() > 0 )
    {
        qDebug() << q.dequeue();
    }
}

Friday, September 10, 2010

Qt Ambassador program

Today my application for Qt Ambassador was accepted by Qt ambassador program. I had submitted crazy chickens game for Qt ambassador program which is now accepted and soon this game will be showcased in Qt Ambassador showcase.

If you also want to become Qt Ambassador then visit this link for more information.

Sunday, September 5, 2010

My visit to Bannerghatta national park

Recently I visited bannerghatta national park, It was great experience seeing animals in front and not in cage. Follwing are few snaps from national park.


















Wednesday, September 1, 2010

Using Signal/Slot with private implementation pattern in Qt

Sometime when using private implementation pattern in Qt, we might want to connect private class's method to signal.

I have seen some code that in such case create slot in public class that call private class's method and connect slot in public class to actual signal but this approach break primary purpose of hiding implementation details from user and also adds unnecessary code.

But using Q_PRIVATE_SLOT macro, we can easily connect private class method to signal. I created following test code to demonstrate usage of Q_PRIVATE_SLOT. Hope this will helps.

In following code I am trying to connection private class's timeOut slot to timer's timeout signal.
#ifndef TEST_H
#define TEST_H

#include <QObject>

class TestPrivate;
class QTimer;

class Test : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(Test)

public:

   Test();
   void testing();
   void testSignal();

private:
   //this will create slot which is implemented in private class
   Q_PRIVATE_SLOT(d_func(),void timeOut());

signals:
    void signal();

private:
    TestPrivate* d_ptr;
};

#endif // TEST_H

#include <QDebug>
#include <QTimer>

class TestPrivate
{
Q_DECLARE_PUBLIC(Test)

public:

TestPrivate(Test* q)
   :q_ptr(q)
{        
   mTimer = new QTimer(q);
   mTimer->setInterval(1000);
   QObject::connect(mTimer,SIGNAL(timeout()),q,SLOT(timeOut()));
   mTimer->start();
}

private:

void testing()
{
    qDebug() << "TestPrivate::testing()";
}

void timeOut()
{
    qDebug() << "TestPrivate::TimeOut()";
}

void testSignal()
{
    qDebug() << "TestPrivate::testSignal()";
    Q_Q(Test);
    emit q->signal();
}

private:// data

QTimer* mTimer;
Test* q_ptr;

};

Test::Test()
:QObject(0),d_ptr( new TestPrivate(this))
{}

void Test::testing()
{
   Q_D(Test);
   d->testing();
}

void Test::testSignal()
{
   Q_D(Test);
   d->testSignal();
}

//dont forget to add moc file, else code will give errors
#include "moc_test.cpp"
main.cpp to test above code.
#include <QCoreapplication>
#include <QDebug>
#include "test.h"
#include <QtTest/QSignalSpy>

int main(int argc,char* argv[])
{
   QCoreApplication app(argc,argv);

   Test test;
   QSignalSpy spy( &test,SIGNAL(signal()));
   test.testSignal();
   qDebug() << "Signal" << spy.count();
   test.testing();
   app.exec();
}