2
votes

I am working with a custom class which emits a signal after fixed interval. This signal is emitting fine as I have connected it with a slot in the same class, and verified with the qdebug statements in slots. The problem is when I try to connect the same signals in mainwindow class, the slots are not being called.
Here is my code:

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "counter.h"
#include <QTextEdit>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

public slots:
    void on_pushButton_clicked();
    void updateText(int);
    void test(int);
    void anotherSlot();

private:
    Ui::MainWindow *ui;
    Counter *cobj;
    int v;
    QTextEdit *te;
};
#endif // MAINWINDOW_H

Mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QThread>
#include "counter.h"

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

    v = 0;
    te = ui->textEdit;
    bool success1 = connect(cobj, SIGNAL (mileStoneReached(int)), this, SLOT(updateText(int)),Qt::AutoConnection);
    bool success2 = connect(cobj,SIGNAL (mileStoneReached(int)), this,SLOT(test(int)),Qt::AutoConnection);
    bool success3 = connect(cobj,SIGNAL (anotherSignal()), this,SLOT (anotherSlot()),Qt::AutoConnection);
    qDebug() << success1 << "   " << success2 << "  " << success3;
}

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

void MainWindow::on_pushButton_clicked()
{
    cobj = new Counter();

    te->setText("0");
    qDebug() <<QThread::currentThreadId();
    cobj->run();
}

void MainWindow::updateText(int x)
{
    qDebug() << Q_FUNC_INFO;
    v = (v+1) * 13;
    te->setText(QString("%1").arg(v));
}

void MainWindow::test( int x)
{
    qDebug() << Q_FUNC_INFO;
    qDebug() <<"___" ;
}

void MainWindow::anotherSlot()
{
    qDebug() << Q_FUNC_INFO;
    qDebug() <<"__######_" ;
}

Counter.h

#ifndef COUNTER_H
#define COUNTER_H
#include <QTimer>

class Counter : public QObject
{
    Q_OBJECT
public:
    Counter(QObject *parent= nullptr);

    void run();
    void reset();
    void init();

signals:
    void mileStoneReached(int x);
    void anotherSignal();

public slots:
    void increment();
    void test();

private:
    int cValue;
    QTimer *timer;
};
#endif // COUNTER_H

Counter.cpp

#include "counter.h"
#include<QDebug>

Counter::Counter(QObject*parent):QObject(parent)
{
    cValue= 0;
    init();
}

void Counter:: init()
{
    timer=new QTimer;
    connect(timer, SIGNAL(timeout()), this, SLOT(increment()),Qt::AutoConnection);
    connect(this,SIGNAL(mileStoneReached(int)), this,SLOT(test()),Qt::AutoConnection);
}

void Counter::reset()
{
    cValue=0;
}

void Counter::run()
{
    timer->start(100);
}

void Counter::increment()
{
    cValue++;
    if(cValue % 13 ==0)
    {
        qDebug() << cValue;
        emit mileStoneReached( cValue);
    }
    else
    {
        emit (anotherSignal());
    }
}

void Counter::test()
{
    qDebug() << "Signal caught";
}

Output:

true     true    true // all connections are fine
0x21ac // Main thread Id  irrelevant to problem
13 // counter value
Signal caught //qdebug  print
26
Signal caught
39
Signal caught
52
Signal caught
65
Signal caught
78
Signal caught
91
Signal caught
104
Signal caught
117
Signal caught
1

1 Answers

1
votes

Inside your MainWindow constructor you instantiate a Counter* and assign it to cobj but in MainWindow::on_pushButton_clicked you create yet another Counter* and again assign it to cobj and then run your counter, this creates several problems.

In MainWindow::on_pushButton_clicked when you create the new Counter* you have a memory leak since you never delete the previous instance, also you call run on the new instance but the connections have been created with the old one that was created inside the MainWindow constructor, so the connected methods won't ever be called.

A possible solution would be to just use the instance create inside the MainWindow constructor.

void MainWindow::on_pushButton_clicked()
{
    te->setText("0");
    qDebug() <<QThread::currentThreadId();

    cobj->run();
}

You also never delete the Counter* inside MainWindow, this causes yet another memory leak, so add delete cobj in your MainWindow destructor.

I suggest to also change the various connections to use the new syntax by using function pointers.

connect(cobj, SIGNAL (mileStoneReached(int)), this, SLOT(updateText(int)),Qt::AutoConnection);

Becomes:

connect(cobj, &Counter::mileStoneReached, this, &MainWindow::updateText,Qt::AutoConnection);

This is safer since some checks are done at compile time, so for example if you make a typo in the function name it won't compile at all.