CroCo
CroCo

Reputation: 5741

custom class with its own QTimer and QThread

I would like to create a class that has its own QTimer and QThread for some projects for Robot's sensors. After some searching, this is what I came up with

#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QObject>
#include <QDebug>


//#####################( Robot Class  )#########################3

class Robot : public QObject
{
public:
    Robot(QObject *parent = 0);
    ~Robot();

private:
    QTimer  *mQTimer;
    QThread *mQThread;

public slots:
    void update();

};

Robot::Robot(QObject *parent)
    : QObject(parent)
{
     mQTimer = new QTimer(0);
    mQThread = new QThread(this);

    mQTimer->setInterval(1);
    mQTimer->moveToThread(mQThread);

    connect(mQTimer, SIGNAL(timeout()), this, SLOT(update()));
    connect(mQThread, SIGNAL(started()), mQTimer, SLOT(start()));

   mQThread->start();
   //mQTimer->start();

}

Robot::~Robot()
{
    delete mQTimer;
    delete mQThread;
}

void Robot::update()
{
    qDebug() << "Robot is updating ...";
}

//##################( Main )###########################
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Robot *myRobot = new Robot(0);

    return a.exec();
}

I'm getting this error

QObject::connect: No such slot QObject::update() in ..\untitled1\main.cpp:34
QObject::connect: No such slot QObject::update() in ..\untitled1\main.cpp:34

Upvotes: 0

Views: 924

Answers (2)

The below works for me. You forgot the Q_OBJECT macro and to include the moc output that defines the static metadata for Robot.

There's of course no point to this code, since the Robot::update slot will execute in the main thread.

Your code has two threads: the main thread, where the Robot object lives, and the robot.mThread, where the timer lives. The timer will time out in the mThread, and will queue a slot call on the main thread. That slot call will end up invoking robot.update with a.exec on the stack.

Note that there's no need to explicitly have the timer and the thread allocated on the heap using new. They should be direct members of Robot, or of its PIMPL.

main.cpp

#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QDebug>

class Robot : public QObject
{
   Q_OBJECT
   QTimer mTimer;
   QThread mThread;
public:
   Robot(QObject *parent = 0) : QObject(parent) {
      connect(&mTimer, &QTimer::timeout, this, &Robot::update);;
      mTimer.start(1000);
      mTimer.moveToThread(&mThread);
      mThread.start();
   }
   Q_SLOT void update() {
      qDebug() << "updating";
   }
};

int main(int argc, char *argv[])
{
   QCoreApplication a(argc, argv);
   Robot robot;
   return a.exec();
}

#include "main.moc"

It would make more sense to move the entire robot to its own thread. Note that when you do that, you need to set parentage on all objects owned by robot, so that they all switch threads along with the Robot object.

The Thread class fixes the long standing usability bug of QThread - it turns it into a truly RAII class that can be safely destructed at any time.

main.cpp

#include <QCoreApplication>
#include <QTimer>
#include <QThread>
#include <QDebug>

class Thread : public QThread {
   using QThread::run;
public:
   ~Thread() { quit(); wait(); }
};

class Robot : public QObject
{
   Q_OBJECT
   QTimer mTimer;
   int mCounter;
public:
   Robot(QObject *parent = 0) : QObject(parent), mTimer(this), mCounter(0) {
      connect(&mTimer, &QTimer::timeout, this, &Robot::update);;
      mTimer.start(1000);
   }
   Q_SLOT void update() {
      qDebug() << "updating";
      if (++mCounter > 5) qApp->exit();
   }
};

int main(int argc, char *argv[])
{
   QCoreApplication a(argc, argv);
   Robot robot;
   Thread thread;
   robot.moveToThread(&thread);
   thread.start();
   return a.exec();
}

#include "main.moc"

Upvotes: 1

Angel.Risteski
Angel.Risteski

Reputation: 566

You are missing the Q_OBJECT macro in your class also try to avoid naming the methods like that because you can mix it with Qt methods names. Also make additional header and cpp file for each class you create in this case make robtot.h and robot.cpp.

class Robot : public QObject
{
Q_OBJECT
public:
    Robot(QObject *parent = 0);
    ~Robot();
...

Upvotes: 3

Related Questions