August
August

Reputation: 100

Use QTimer with its timeout event in another class of the project

I'm using Qt 5.7 trying to use a timer with timeout event in a class named MyClass. I created a public variable of this class in mainwindow.h. I put the timer's slot connect in the constructor of MyClass, and have a function in MyClass to start the timer. But when I execute the function, the timer slot doesn't work. I have no error in building, but I get the comment below on the application window at run time: QObject::connect: No such slot QObject::on_timeout()

Here is my code:

The mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "myclass.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MyClass mc;
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

The mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "myclass.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    mc.TimerStart();
}

myclass.h

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QTimer>

class MyClass : public QObject
{
public:
    MyClass();
    TimerStart();

    QTimer *timer;

public slots:
    on_timeout();
};

#endif // MYCLASS_H

myclass.cpp

#include "myclass.h"
#include <QMessageBox>
#include <QTimer>

MyClass::MyClass()
{
    timer = new QTimer(this);
}

MyClass::TimerStart()
{
    timer->setInterval(1000);
    connect(timer, SIGNAL(timeout()), this, SLOT(on_timeout()));
    timer->start(1000);
}

MyClass::on_timeout()
{
    QMessageBox msg;
    msg.setText("updated");
    msg.exec();
}

Upvotes: 1

Views: 4499

Answers (2)

  1. You forgot to add the Q_OBJECT to MyClass,
  2. You're reentering the event loop in on_timeout.
  3. You're setting the timer's interval multiple times.
  4. You're connecting to the timer's signal multiple times.
  5. You're making an implementation detail (the on_timeout slot) public.
  6. You're pessimizing your code by manually managing the memory for QTimer.
  7. You're including <QTimer> twice.
  8. It's 2016 and you're not using C++11. Yes, you can use it even with Qt 4.

Here's how I'd write it:

Qt 5

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QTimer>
#include <QMessageBox>

class MyClass : public QObject
{
    Q_OBJECT
    QMessageBox msg;
    QTimer timer{this};
public:
    explicit MyClass(QObject * parent = nullptr);
    void timerStart();
};

#endif // MYCLASS_H
#include "myclass.h"

MyClass::MyClass(QObject * parent) : QObject{parent}
{
    msg.setText(QStringLiteral("updated"));
    connect(&timer, &QTimer::timeout, &msg, &QMessageBox::show);
}

void MyClass::timerStart()
{
    timer.start(1000);
}

Qt 4

Here I demonstrate that implementation details should be private. You could of course do as above and set the msg's text in the constructor, and connect directly to the msg's SLOT(show()).

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QTimer>
#include <QMessageBox>

class MyClass : public QObject
{
    Q_OBJECT
    QMessageBox msg;
    QTimer timer{this};
    Q_SLOT void on_timeout();
public:
    explicit MyClass(QObject * parent = nullptr);
    void timerStart();
};

#endif // MYCLASS_H
#include "myclass.h"

MyClass::MyClass(QObject * parent) : QObject{parent}
{
    connect(&timer, SIGNAL(timeout()), SLOT(on_timeout()));
}

void MyClass::timerStart()
{
    timer.start(1000);
}

void MyClass::on_timeout()
{
    msg.setText("updated");
    msg.show();
}

Upvotes: 6

rocambille
rocambille

Reputation: 15976

You forgot to add Q_OBJECT in your class declaration:

class MyClass : public QObject
{
    Q_OBJECT
    // ...

If you're using Qt 5.7, you should use the Qt5 syntax for connect:

connect(timer, &QTimer::timeout, this, &MyClass::on_timeout);

By doing so, the connection will be evaluated at compile time instead of runtime. Moreover, you can connect a signal to functions even if they are not declared as slots (so you won't need the Q_OBJECT identifier in the class declaration).

More info here.

Upvotes: 3

Related Questions