I want to write a simple Application which launches a thread to do some computations. The worker thread should periodically send signals to the MainWindow to inform it about the current state of progress. In order to implement the worker thread, I subclass QThread and reimplement the run method. When I compile the program using QTCreator, I always get these two errors:
In the Header file of Worker, which implements the working thread:
.../worker.h:7: error: undefined reference to `vtable for Worker'
In the Source file of MainWindow, when I try to connect the Worker signal to the MainWindow slot:
.../worker.cpp:23: error: undefined reference to `Worker::updateLabelSig(int)'
Worker.h
#ifndef WORKER_H
#define WORKER_H
#include <QThread>
#include <vector>
class Worker : public QThread
{
Q_OBJECT
void run() override;
private:
void computeNumbers();
std::vector<int> foundNumbers;
int upperLimit;
signals:
void updateLabelSig(int);
};
#endif // WORKER_H
Worker.cpp
#include "worker.h"
void Worker::run(){
exec();
computeNumbers();
}
void Worker::computeNumbers(){
upperLimit=1e5;
foundNumbers.push_back(1);
for(int i=2; i<upperLimit; i++){
/////////////do some calculations and emit regular signals to inform main window///////////////////
if(i%10000==0)
emit updateLabelSig(i);
}
}
In the MainWindow class, I have a button which should launch the thread if clicked:
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include <QLabel>
#include "worker.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_mainbutton_clicked()
{
Worker* w=new Worker;
QObject::connect(w,SIGNAL(Worker::updateLabelSig(int)),this,SLOT(updateLabel(int)));
w->start();
}
void MainWindow::updateLabel(int i){
findChild<QLabel*>("mainlabel")->setText(QString("Numbers searched so far: ")+QString::number(i));
}
Ok, it turned out that I simply needed to rerun qmake in order to get things to work. When I first wrote the header file worker.h I forgot to add the Q_OBJECT macro which I added later. However, I didn't run qmake.
Related
Hello Im trying to print my result from a thread to textBrower in qtwidget QT but I cant, either I get error or the program wont compile
is there another way ?? how can I change the textBrowser outside of the class's function??
PS BTW I need to keep looping inside the thread cuz actually im getting some data from uart in final program (in this code i just wanna print "lol" which eventually I wanna change it with some other code which take data ) so I cant come out of the loop
eventually i want use some process from another library and show the resault REAL TIME
bool stop;
out::out(QWidget *parent) :
QWidget(parent),
ui(new Ui::out)
{
ui->setupUi(this);
ui->textBrowser->setText("lol");
}
out::~out()
{
delete ui;
}
///////////////////////////////////////////////
class t : public out, public QThread
{
public:
void run()
{
while(1){
qDebug()<<"hi"<<i;
// ui->textBrowser->setText("lol"); I tried to use this but it didnt worked
if(stop==true){
QThread::exec();
}
}
}
};
void mamad1(void){ //this function get called from another cpp file and its for starting the thread
stop=false;
t *b = new t;
b->start();
}
void out::on_pushButton_clicked() // a push button to stop the thread
{
stop=true;
}
I tried make ui in out.h file a public property and use ui->textBrowser->setText("lol"); but it didn't worked the program freezed and i got this
error : (Parent is QTextDocument(0x208d812a510), parent's thread is QThread(0x208d6816de0), current thread is QThread(0x208dac94e10)
I tried to use connect() also and didn't worked or I didn't use it right
The concept of QT the GUI thread is called the master thread. This thread has an event queue. In general, this event queue is populated by internal and external events. Moreover, the queue between threads is an efficient approach for thread communication. The same is true for the worker threads as well. When you call the start method through the worker threads their signal queue is created and ready to be consumed by the corresponding thread.
Let's come back to your question. The solution is simple. From your worker threads, you can just send a signal to the master thread. The master thread will see this event that modifies the GUI item and forwards this signal/event to the slot that is responsible to take action accordingly. Just define a signal in your worker thread and connect your master thread to this signal with a given slot.
UPDATE FOR SOLUTION
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <MyWorkerThread.h>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void setWorkerThread(MyWorkerThread* thread);
void connectToSignals();
public slots:
void handleTextBoxSignal(const QString& text);
private:
Ui::MainWindow *ui;
MyWorkerThread* m_worker_thread{nullptr};
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
void MainWindow::setWorkerThread(MyWorkerThread* thread)
{
m_worker_thread = thread;
}
void MainWindow::connectToSignals()
{
QObject::connect(m_worker_thread,
SIGNAL(changeTextOnUI(QString)),
this,
SLOT(handleTextBoxSignal(QString)));
}
void MainWindow::handleTextBoxSignal(const QString& text)
{
qDebug() << "Text box change signal received with text: " << text;
auto text_box = findChild<QTextEdit*>("myTxtEdit");
if(text_box != nullptr)
{
text_box->setText(text);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
MyWorkerThread.h
#ifndef MYWORKERTHREAD_H
#define MYWORKERTHREAD_H
#include <QObject>
#include <QThread>
class MyWorkerThread : public QThread
{
Q_OBJECT
public:
MyWorkerThread(QObject* parent = nullptr);
void stopThread();
signals:
void changeTextOnUI(const QString& text);
private:
void run() override;
bool m_exit{false};
};
#endif // MYWORKERTHREAD_H
MyWorkerThread.cpp
#ifndef MYWORKERTHREAD_H
#define MYWORKERTHREAD_H
#include <QObject>
#include <QThread>
class MyWorkerThread : public QThread
{
Q_OBJECT
public:
MyWorkerThread(QObject* parent = nullptr);
void stopThread();
signals:
void changeTextOnUI(const QString& text);
private:
void run() override;
bool m_exit{false};
};
#endif // MYWORKERTHREAD_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
MyWorkerThread* worker_thread = new MyWorkerThread();
w.setWorkerThread(worker_thread);
w.connectToSignals();
worker_thread->start();
w.show();
return a.exec();
}
In the above code, you see the full solution to your problem. In the worker thread, we increment a static counter and concatenate it with a string and send it to the master thread that manages the UI elements. We emit a signal and this signal is landed on the slot. This way the master thread updates the text box on the screen per 5 seconds. The worker thread sleeps for 5 seconds at each iteration.
I'm writing a QT application and everything is fine with building and working but when i close the app with a thread running, the app closes and shows a message:
[Runtime Error....].
The application output says:
QThread: Destroyed while thread is still running
The program has unexpectedly finished.
The process was ended forcefully.
example crashed.
how to solve that ?
Example:
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QString>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
example = new Thread(this);
connect(example, SIGNAL(print_line(QString)), this, SLOT(print_line2(QString)), Qt::BlockingQueuedConnection);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::print_line2(QString in)
{
ui->textBrowser->append(in);
}
void MainWindow::on_pushButton_clicked()
{
example->start();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <Thread.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Thread *example;
public slots:
void print_line2(QString in);
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Thread.cpp
#include "Thread.h"
#include <windows.h>
using namespace std;
Thread::Thread(QObject *parent):
QThread(parent)
{
}
Thread::~QThread()
{
delete ui;
}
void Thread::print(QString in)
{
print_line(in);
}
void Thread::run()
{
int count = 0;
for(;;) {
Sleep(100);
count += 1;
print(QString::number(count));
}
}
Thread.h
#ifndef READINFO_H
#define READINFO_H
#include <QThread>
class Thread : public QThread
{
Q_OBJECT
public:
explicit Thread(QObject *parent =0);
void print(QString in);
void run();
signals:
void print_line(QString x);
};
#endif
Ready example
The problem is that the thread is still in the running state when your application shuts down.
The code inside Thread::Run() contains an infinite loop -- there is no way for it to terminate by itself. You need to write your thread so that it will exit, or at the very least, you need to forcefully terminate the thread before your app closes.
To forcefully terminate, you could add two lines of code to the MainWindow destructor like so:
MainWindow::~MainWindow()
{
example->terminate();
example->wait();
(...)
}
I cannot produce a very simple example to getting start with Qt multi-thread. I read a lot of posts and tutorials but still it doesn't work.
Goal
Have a background worker independent from the GUI. Oh, wow...
What I did
A simple example:
create the Engine class
that shows a QMainWindow
and starts a QTimer that prints a number
But if you left-click the title bar of the GUI, keeping pressed the mouse button (i.e. on the minimize button) the counter will stop! Even if it was created in a non-GUI environment and it was moved in another thread!
Why?
main.cpp
#include "engine.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Engine e;
return a.exec();
}
engine.h
#ifndef ENGINE_H
#define ENGINE_H
#include <QObject>
#include <QThread>
#include <QTimer>
#include "mainwindow.h"
class Engine : public QObject
{
Q_OBJECT
public:
explicit Engine(QObject *parent = 0);
private:
MainWindow mainWindow;
QThread *thread;
QTimer *timer;
private slots:
void foo();
};
#endif // ENGINE_H
engine.c
#include "engine.h"
#include <QDebug>
Engine::Engine(QObject *parent) : QObject(parent)
{
thread = new QThread(this);
timer = new QTimer();
timer->setInterval(100);
connect(timer, &QTimer::timeout, this, &Engine::foo);
connect(thread, &QThread::started, timer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
timer->moveToThread(thread);
thread->start();
mainWindow.show();
}
void Engine::foo()
{
static int i;
qDebug() << ++i;
}
The QMainWindow contains no code.
Basically, Qt has one thread dealing with the GUI (typically the main thread). Any objects specific to this thread will be blocked by GUI work. You need to keep the GUI outside of your interacting partners.
To be more specific, your Engine object resides in the GUI/main thread. Even while your timer is sent to a worker thread, its signals are dispatched to the slot foo() in the main thread.
You need to de-mangle Engine and the main window such that Engine can reside in its own thread and process signals while the GUI is blocking.
Looks like you moved QTimer instance to your custom thread, but you didnt move Engine instance to this thread, therefore, foo slot of Engine class will be executed in main thread.
I can suggest you using additional helping QObject-derived class instance within Engine class and move it to your new thread in Engine constructor.
With following changes solution works fine even with minimize button pressed (I've commented places where i added or changed anything. Also added new QObject-derived class EngineWorker):
Engine.h
#ifndef ENGINE_H
#define ENGINE_H
#include <QObject>
#include <QThread>
#include <QTimer>
#include "mainwindow.h"
#include "engineworker.h"
class Engine : public QObject
{
Q_OBJECT
public:
explicit Engine(QObject *parent = 0);
private:
MainWindow mainWindow;
QThread *thread;
QTimer *timer;
//additional QObject-derived class
EngineWorker *worker;
private slots:
void foo();
};
#endif // ENGINE_H
Engine.cpp
#include "engine.h"
#include <QDebug>
Engine::Engine(QObject *parent) : QObject(parent)
{
thread = new QThread(this);
timer = new QTimer();
//Creating instance of Engine worker
worker = new EngineWorker();
timer->setInterval(100);
//Connecting Engine worker' foo slot to timer
connect(timer, &QTimer::timeout, worker, &EngineWorker::foo);
connect(thread, &QThread::started, timer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
timer->moveToThread(thread);
//Moving worker to custom thread
worker->moveToThread(thread);
thread->start();
mainWindow.show();
}
void Engine::foo()
{
static int i;
qDebug() << ++i;
}
EngineWorker.h
#ifndef ENGINEWORKER_H
#define ENGINEWORKER_H
#include <QObject>
#include <QDebug>
class EngineWorker : public QObject
{
Q_OBJECT
public:
explicit EngineWorker(QObject *parent = 0);
signals:
public slots:
void foo();
};
#endif // ENGINEWORKER_H
EngineWorker.cpp
#include "engineworker.h"
EngineWorker::EngineWorker(QObject *parent) : QObject(parent)
{
}
//foo slot of EngineWorker class
void EngineWorker::foo()
{
static int j;
qDebug() <<"Worker: "<< ++j;
}
I tried to use a simple QTimer object on my window widget so that I can calculate the elapsed time a method takes to complete. But to my astonishment, the timer was blocked until the method completes execution! i.e when the method in question ends, the timer starts ticking!
Here is a sample code to demonstrate what I wrote:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_btnTest_clicked();
void OnTimerTick();
private:
Ui::MainWindow *ui;
ulong seconds;
};
#endif // MAINWINDOW_H
And this is the cpp file:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv/cv.h"
#include <QTimer>
#include <QtCore>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_btnTest_clicked()
{
QTimer * timer = new QTimer(0);
seconds =0;
connect(timer,SIGNAL(timeout()),this,SLOT(OnTimerTick()));
timer->setInterval(100);
timer->start();
QThread::sleep(5);//simulating a method which takes 5 seconds to complete
//timer->stop();
}
void MainWindow::OnTimerTick()
{
ui->lblElapsedTime->setText(QString::number(++seconds));
}
How can I get the asynchronous behavior, something like what we have in C# i.e. where the Timer runs its own thread of execution?
Update:
Thanks for the clarification, now how can I incorporate Qthreads with the timer, Do I have to inherit from Qthreads and use timer in my child class or do I have to inherit from QTimer and have a thread executed in it! It's really confusing!
This is common behavior for Qt, WinForms, WPF etc.
All UI-related events are executed synchronously one-by-one on the UI thread. Event handlers are not expected to perform long executions to avoid blocking. If you want to execute a long task, you should do it in other thread.
QTimer is designed to raise events on the UI thread. This is good because you are sure that no other event handlers are executing at that moment.
I want to run two threads concurrently. I successfully did the same when I ran a program as a QT console application.
Here's the working code of QT console application for multi threading:-
myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
#include <QDebug>
#include <QThread>
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject *parent = 0);
void doSetup(QThread &cThread);
void doSetup2(QThread &cThread2);
signals:
public slots:
void doWork();
void doWork2();
};
#endif // MYOBJECT_H
main.cpp:
#include <QtCore/QCoreApplication>
#include <QThread>
#include <myobject.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThread cThread, cThread2;
MyObject cObject, cObject2;
cObject.doSetup(cThread);
cObject.moveToThread(&cThread);
cObject2.doSetup2(cThread2);
cObject2.moveToThread(&cThread2);
cThread.start();
cThread2.start();
qDebug()<<"hello there ";
return a.exec();
}
my object.cpp
#include "myobject.h"
#include <QThread>
#include "tftpServer.h"
MyObject::MyObject(QObject *parent) :
QObject(parent)
{
}
void MyObject::doSetup(QThread &cThread)
{
connect(&cThread, SIGNAL(started()), this, SLOT(doWork()));
}
void MyObject::doSetup2(QThread &cThread2)
{
connect(&cThread2, SIGNAL(started()), this, SLOT(doWork2()));
}
void MyObject::doWork()
{
for(int i=0; i<1000; i++)
{
qDebug()<<"******************Thread 1";
}
}
void MyObject::doWork2()
{
for(int i=1000; i<2000; i++)
{
qDebug()<<"Thread 2************************";
}
}
Here's the output:
******************Thread 1
Thread 2************************
******************Thread 1
Thread 2************************
******************Thread 1
Thread 2************************
******************Thread 1
Thread 2************************
..and so on
Now when I use this almost same code and run as a QT GUI application, the threads do not run concurrently, but run one after the other. Here's the code:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QThread>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void doSetup(QThread &cThread);
void doSetup2(QThread &cThread2);
private:
Ui::MainWindow *ui;
public slots:
void doWork();
void doWork2();
};
#endif // MAINWINDOW_H
main.cpp
#include <QtGui/QApplication>
#include "mainwindow.h"
#include <QThread>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QThread cThread, cThread2;
MainWindow cObject, cObject2;
cObject.doSetup(cThread);
cObject.moveToThread(&cThread);
cObject2.doSetup2(cThread2);
cObject2.moveToThread(&cThread2);
cThread.start();
cThread2.start();
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>
#include <qthread.h>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug()<<"gui running";
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::doSetup(QThread &cThread)
{
connect(&cThread, SIGNAL(started()), this, SLOT(doWork()));
}
void MainWindow::doSetup2(QThread &cThread2)
{
connect(&cThread2, SIGNAL(started()), this, SLOT(doWork2()));
}
void MainWindow::doWork()
{
//QThread::sleep(100);
for(int i=0; i<1000; i++)
{
qDebug()<<"******************Thread 1";
// qDebug()<<i;
}
}
void MainWindow::doWork2()
{
for(int i=1000; i<2000; i++)
{
qDebug()<<"Thread 2************************";
// qDebug()<<i;
}
}
Here's the output:
gui running
gui running
QObject::moveToThread: Widgets cannot be moved to a new thread
QObject::moveToThread: Widgets cannot be moved to a new thread
gui running
******************Thread 1
******************Thread 1
******************Thread 1
******************Thread 1
(and so on...)
******************Thread 1
Thread 2************************
Thread 2************************
Thread 2************************
Thread 2************************
Thread 2************************
Thread 2************************
(and so on...)
Note that the only difference b/w console and gui application I made is changed the base class QObject to QMainWindow, and hence the thread objects so created are objects of QObject & QMainWindow respectively, for console and GUI applications.
Hoping I am sufficiently clear, can you please tell me what mistake am I committing, which is making the threads run one after the other and not concurrently, as it does for the console application?
Thank you.
Any class inherited from QWidget cannot reside in thread other than the main GUI thread. Actually this is what the output said. Your solution is a bad design. Separate the work objects (inherited from QObject, residing in another thread) and the visual objects (inherited from QWidget, residing in the GUI thread), to follow the "one class one responsibility" principle.
Another catch in multithreading in Qt is the fact that any QObject cannot reside in different thread than its parent. This is natural because the parent is the owner of the child object, most importantly it takes care of its destruction. To enable this, the child cannot be in other thread. Otherwise the parent might destroy an executing child, for example.
There are yet more catches, for example QPixmap cannot be in other thread than the main GUI etc.