I am new to qt and want to make a thread which sends an integer signal and I have a mainwindow that recieves the signal and I am sure the signal is delivered as I used cout to see it but when I want to sent recieved number to spinbox (or label) placed in ui the main thread is stuck and does not show anything.
here is my thread class:
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QtCore>
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
bool Stop;
signals:
void NumberChanged(int);
public slots:
};
#endif // MYTHREAD_H
cpp file of thread:
#include "mythread.h"
#include <QtCore>
MyThread::MyThread(QObject *parent) :
QThread(parent)
{
}
void MyThread::run()
{
for(int i=0;i<2000000;i++){
QMutex m;
emit NumberChanged(i);
QThread::msleep(100);
}
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "mythread.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
MyThread *mthread;
private:
Ui::MainWindow *ui;
private slots:
void on_pushButton_clicked();
public slots:
void onNumberChanged(int num);
};
#endif // MAINWINDOW_H
and finally mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
mthread = new MyThread(this);
connect(mthread,SIGNAL(NumberChanged(int)),this,SLOT(onNumberChanged(int)));
mthread->property(Q)
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onNumberChanged(int num)
{
cout << num << endl;
ui->spinBox->setValue(num);
}
void MainWindow::on_pushButton_clicked()
{
mthread->run();
}
when i run this, the integer value is shown by cout but the spinbox or label doesnt change at all until number reaches the 2000000. whats wrong?
You need to start the thread by invoking its start()
method, not the run()
method. Your thread implementation incorrectly makes run()
a public method: this allowed you to make this mistake - otherwise it'd be impossible by construction. run()
should be protected
, not public
.
You would probably also want to interrupt the loop when a thread interruption is requested (c.f. QThread::requestInterruption()
and QThread::isInterruptionRequested()
). You also need to make the thread destructible at any time, so that when you exit the application the thread winds down cleanly.
Finally, you'd want to decouple the thread from the user interface: the window doesn't need to know about the thread, and vice-versa. They should be connected through a compatible interface, e.g. via signals and slots.
Thus, I'd first transform your code into:
#include <QtWidgets>
class MyThread : public QThread
{
Q_OBJECT
public:
using QThread::QThread;
~MyThread() { requestInterruption(); wait(); }
void run() override {
for(int i=0; i<2000000 && !isInterruptionRequested(); i++) {
emit numberChanged(i);
QThread::msleep(100);
}
}
Q_SIGNAL void numberChanged(int);
};
class Window : public QWidget
{
Q_OBJECT
QVBoxLayout m_layout{this};
QPushButton m_start{"Start"};
QPushButton m_stop{"Stop"};
QSpinBox m_box;
public:
Window() {
m_layout.addWidget(&m_start);
m_layout.addWidget(&m_stop);
m_layout.addWidget(&m_box);
connect(&m_start, &QPushButton::clicked, this, &Window::reqStart);
connect(&m_stop, &QPushButton::clicked, this, &Window::reqStop);
}
Q_SIGNAL void reqStart();
Q_SIGNAL void reqStop();
Q_SLOT void setNumber(int n) {
m_box.setValue(n);
}
};
int main(int argc, char **argv) {
QApplication app{argc, argv};
MyThread t;
Window w;
QObject::connect(&w, &Window::reqStart, &t, [&t]{ t.start(); });
QObject::connect(&t, &MyThread::numberChanged, &w, &Window::setNumber);
QObject::connect(&w, &Window::reqStop, &t, &MyThread::requestInterruption);
w.show();
return app.exec();
}
#include "main.moc"
The second transformation would involve moving the loop into a QObject
, and using a generic safe thread to host it - that process is detailed in this answer.
A third transformation might involve the use of Qt Concurrent module to parallelize the computation across multiple threads, if possible.