Search code examples
c++qtsignals-slotsqthread

Trying to connect an emit signal, but nothing appears on the other side


So, I am learning my way around QThread and I understand it to a reasonable extent.

However, I am trying to implement a class derived from QThread to do a basic function, then emit a signal if a value has changed.

Let me post the Header and Source files:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>

#include "mythread.h"

#include <QTextEdit>
#include <QPushButton>
#include <QSpinBox>
class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();

    void setGUI();

    void Start_Thread();
    void Stop_Thread();  //will be implemented later to stop all threads

public slots:
    void Update_O1(int);

private:
    MyThread *m_Thread1;

    QPushButton *START;
    QPushButton *STOP;

    QSpinBox *L1Input;
    QSpinBox *L2Input; //For when a second Thread is added
    QSpinBox *L3Input; //For when a third Thread is added

    QTextEdit *L1Out;
    QTextEdit *L2Out; //For when a second Thread is added
    QTextEdit *L3Out; //For when a third Thread is added
};
#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include <QGridLayout>

Dialog::Dialog(QWidget *parent)
    : QDialog(parent), m_Thread1(new MyThread), START(new QPushButton("Start")),
      STOP(new QPushButton("Stop")), L1Input(new QSpinBox), L2Input(new QSpinBox),
      L3Input(new QSpinBox),L1Out(new QTextEdit),L2Out(new QTextEdit), L3Out(new QTextEdit)
{
    setGUI();
    connect(START, &QPushButton::clicked, this, &Dialog::Start_Thread);
    connect(STOP, &QPushButton::clicked, this, &Dialog::Stop_Thread);

    connect(m_Thread1, SIGNAL(NumberChanged(int)), this, SLOT(Update_01(int))); 
//I know this is the old Syntax, but I don't know how else to do this...yet.
//I got a similar function to work on a different project using the same format
}

Dialog::~Dialog()
{
}

void Dialog::setGUI()
{
    setWindowTitle("Three Threads");

    resize(300,300);

    START->setMaximumWidth(100);
    STOP->setMaximumWidth(100);

    L1Input->setRange(1,100);
    L2Input->setRange(1,100);
    L3Input->setRange(1,100);

    L1Out->setReadOnly(true);
    L2Out->setReadOnly(true);
    L3Out->setReadOnly(true);

    QGridLayout *GLout = new QGridLayout;
    GLout->addWidget(START,0,1);
    GLout->addWidget(STOP,0,2);

    GLout->addWidget(L1Input,1,0);
    GLout->addWidget(L2Input,1,1);
    GLout->addWidget(L3Input,1,2);

    GLout->addWidget(L1Out,2,0);
    GLout->addWidget(L2Out,2,1);
    GLout->addWidget(L3Out,2,2);

    setLayout(GLout);
}

void Dialog::Start_Thread()
{
    qDebug() << "START works";  //this is just to let me know the Start_Thread function is called properly
    m_Thread1->start();
}

void Dialog::Stop_Thread()
{
}

void Dialog::Update_O1(int x)
{
    qDebug() << QString::number(x);
}

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QObject>

class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = nullptr);

    void run();

    void setSnum(int); //setter function

    bool Stop = false; //will be used later to stop a thread

signals:
    void NumberChanged(int);

private:
    int Snum = 10; //temporary value. will later implement setter to use value from GUI
};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include <QDebug>
#include <QtCore>

MyThread::MyThread(QObject *parent)
    : QThread{parent}
{
}

void MyThread::run()
{

    while(!(Snum == 1))
    {
        QMutex mutex;
        mutex.lock();
        if(this->Stop) break;
        mutex.unlock();

        if(Snum % 2 == 0)
        {
            Snum /= 2;
        }else{
            Snum *= 3;
            Snum += 1;
        }
        emit this->NumberChanged(Snum);
    }
}

void MyThread::setSnum(int startnum)
{
    Snum = startnum;
}

Lastely, a very basic main.cpp file

#include "dialog.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog w;
    w.show();
    return a.exec();
}

The problem I am facing though is that I don't seem to be getting a signal from the emit function in mythread.cpp's run function. I am not getting an output in the qDebug() section of QtCreator.
What am I doing wrong?

I am using Qt 6.3.0.


Solution

  • You have this connection:

    connect(m_Thread1, SIGNAL(NumberChanged(int)), this, SLOT(Update_01(int)));
    

    But your method is actually called like this:

    void Dialog::Update_O1(int x)
    

    Note Update_01 vs. Update_O1. They are different characters. One is zero and the other is capital 'o'.

    So, you should have:

    connect(m_Thread1, SIGNAL(NumberChanged(int)), this, SLOT(Update_O1(int)));
    

    However, the best solution is to use the "new" signal-slot syntax.

    connect(m_Thread1, &QThread::NumberChanged, this, &QDialog::Update_O1);
    

    Actually, if the slot is short, you could even use a lambda:

    connect(m_Thread1, &QThread::NumberChanged, this, [](int x) {qDebug() << QString::number(x);});
    

    The major advantage of the new signal-slot syntax is that this sort of issue would be caught at compilation time rather than runtime. So, you would not potentially release your software with this bug.