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();
}

3 comments:

  1. Is this subject connected with your profesыional sphere or is it more about your hobbies and free time?

    ReplyDelete
  2. once it used to be connected with professional work, but now it's just hobby work

    ReplyDelete
  3. Thank you for your code. Isn't the pointer delete missing (without using QScopedPointer for d_ptr)?

    ReplyDelete