How do I invalidate canvas of an object owned by another thread? - c++

I want to load data in a separate thread and than to call redraw method to invalidate canvas and draw the data. However, when I call redraw method, it triggers breakpoint with following message:
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by different thread..."
I'm looking for some sort of dispatch method that could be used to call the function in the correct thread.
What is the proper way to do this is Qt5?

The general idea is to send a signal from worker thread back to the main thread which then triggers the redraw. Something like this (I haven't tested it):
class Worker : public QObject
{
Q_OBJECT
public:
...
void loadData()
{
... // Do stuff
emit dataLoaded();
}
}
class MainWindow : public QObject
{
Q_OBJECT
public:
MainWindow()
{
Worker *worker = new Worker;
worker->moveToThread(workerThread);
connect(&workerThread, &QThread::started, worker, &Worker::loadData);
connect(worker, &Worker::dataLoaded, this, &MainWindow::redraw);
workerThread.start();
}
public slots:
void redraw()
{
// Do your redrawing here
}
private:
QThread workerThread;
}

Related

QT slot not getting called on main thread

From the thread context of a slot in my QT GUI application (upon button push), I am trying to launch a worker thread to update other another part of the GUI with the results of a CPU intensive calculation - these results will update a table or a google like map widget - so this needs to occur in the main QT application thread where it is safe to update these widgets.
The problem I have is that the updateGUIWidget slot never gets called unless I change the connection type to Qt::DirectConnection - in which case it gets called in the worker thread (where it is unsafe to update the GUI). I checked the results of each of the connect calls and they are fine, it seems that there is some issue with the event loop somewhere. I'm not sure if I need to allocate the thread and the worker objects as members of the mainwindow or if its OK to do so from stack variables in the slot.
void
mainwindow::on_importSimulatedFlight_clicked()
{
// experimental worker thread model adapted from YouTube tutorial
// by Giuseppe di Angelo https://www.youtube.com/watch?v=BgqT6SIeRn4
// auto thread = new QThread;
// note worker created in gui thread here - we will move its thread
// affinity to 'thread' below before starting it.
auto thread = new QThread;
auto worker = new Worker;
connect(thread, &QThread::started, worker, &Worker::doWork);
// connect(worker, &Worker::progressUpdate, this, &mainwindow::updateGUIWidget, Qt::DirectConnection);
connect(worker, &Worker::progressUpdate, this, &mainwindow::updateGUIWidget, Qt::QueuedConnection);
connect(worker, &Worker::workDone, thread, &QThread::quit);
connect(thread, &QThread::finished, worker, &Worker::deleteLater);
// move worker to separate thread
worker->moveToThread(thread);
thread->start();
}
The mainwindow has a slots declared in mainwindow.h as follows:
class mainwindow : public QMainWindow
{
Q_OBJECT
public:
explicit mainwindow(QWidget *parent = Q_NULLPTR);
~mainwindow();
...
public slots:
void on_importSimulatedFlight_clicked();
void updateGUIWidget(const param& rParam);
...
}
and implemented in mainwindow.cpp as follows:
void
mainwindow::updateGUIWidget(const param& rParam)
{
... update widget components with rParam partial result here
}
and my worker is as follows:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork() {
const QString result;
for (int i=0; i<5; i++) {
const MMRTimedRecord foo;
// QThread::sleep(1);
emit progressUpdate(foo);
}
emit workDone(result);
}
signals:
void progressUpdate(const MMRTimedRecord&);
void workDone(const QString &result);
};
The reason it isn't working is because there's a serious flaw in your code: you are trying to emit a reference to a local variable to be handled in an slot on a different thread. That is a recipe for disaster.
When you are using Qt::QueuedConnection, you MUST emit by value, like this:
void progressUpdate(MMRTimedRecord val);
That means that your MMRTimedRecord must be copyable, and correspondingly, your slot must also accept by value. And why is there a mismatch between the signal progressUpdate(const MMRTimedRecord&) and the slot updateGUIWidget(const param& rParam); ?
You can check this answer for a possible solution. You can do
MainThreadEvent::post([&]()
{
// gui update stuff
}
);
in your slot to do the gui update in the main thread, but it is a crude approach to be sure. Despite this, I do something like this all the time. Be careful of dangling pointers and references (use QPointer)..., as the issued event is independent of the issuing object. Alternatively, use the timer approach.
It’s really easy – and you shouldn’t be managing any threads manually:
void Ui::slot() {
QtConcurrent::run([this]{
auto result = compute();
QMetaObject::invokeMethod(this, [this, r = std::move(result)]{
m_widget.setSomething(r);
});
});
}
The type of the data you compute should be movable.

Qt moveToThread, signals/slots with arguments

I've tried to use an approach from https://wiki.qt.io/QThreads_general_usage
with moveToThread. Everything is fine. But if I try to add the argument to the finished signal, there is the following problem:
class Worker : public QObject {
Q_OBJECT
public:
Worker();
~Worker();
public slots:
void process();
signals:
void finished(const std::string& value);
};
void Worker::process() { // Process. Start processing data.
// allocate resources using new here
qDebug("Hello World!");
std::string s = someFunctionReturningString();
emit finished(s);
}
The main class is:
class Main: public QObject {
Q_OBJECT
public:
void startProgram();
public slots:
void slotFinished(const std::string& s);
};
void Main::startProgram() {
QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(thread, &QThread::started, worker, &Worker::process);
connect(worker, &Worker::finished, thread, &QThread::quit);
connect(worker, &Worker::finished, worker, &Worker::deleteLater);
connect(worker, &Worker::finished, this, &Main::slotFinished);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();
}
void Main::slotFinished(const std::string& value) {
qDebug() << "result " << value.c_str();
}
If I connect this finished signal to some slot (slotFinished), I didn't get the call of this slot.
Is it an expected behavior of the signals/slots/moveToThread?
Problem is meta data information.
When you do a default connection between signal and slot and when signal is emitted from different thread than receiver is assigned to, Qt does a magic and wraps arguments for signal (creates a copy) and queue them in event loop of destination thread.
Then when destination tread executes logic of the Qt event loop, values are unwrapped and respective slot is invoked with copied values.
Now to be able to do this copy, Qt has to have some minimal knowledge about that type.
So when you use Qt types it will work out of the box, but you use external types like std::string in your case, you have to first perform type registration.
So basically your code is missing something like this:
// to be declared somewhere
Q_DECLARE_METATYPE(std::string);
// to be invoked at the beginning of program
qRegisterMetaType<std::string>();
Without type registration Qt doesn't know how to do a copy and provides a warning in logs. Check Qt logs I'm sure it prompts you with proper error message.

Deletelater not responding in qt

I am asking this question second time and I did not find a solution that I am not so familiar with qt events.This is my code:
class My_worker :public QObject{};
I have a function in that class that will send data periodically with a timer in it.
My_worker::process{
Qtimer my_timer=new Qtimer();
my_timer->setInterval(time_ms);
connect(my_timer,SIGNAL(timeout()),this(sendData()))
}
So with function sendData() I am sending data with the my_timer elapsed. this is my thread doing the work. I create these in my QCoreapplication class. so:
class My_Application: public QCoreApplication{};
In constructor I define the signals and threaa like this.
My_Application::My_Application{
//First I create an object of My_worker
My_worker my_worker=new My_worker();
//Then I create a thread and move my worker to thread
QThread my_thread=new QThread();
my_worker->moveToThread(my_thread);
// then I connect the signals.
connect(my_thread,SIGNAL(started)),my_worker,SLOT(process())); //So starts processing
connect(my_worker,SIGNAL(finished()),my_thread,SLOT(quit()));
connect(my_thread,SIGNAL(finished()),my_thread,SLOT(deleteLater))));
connect(my_worker,SIGNAL(finished()),my_worker,SLOT(deleteLater()));
}
And finally my dataSend() function is;
void dataSend(){
//do some work
// **if I emit my finished signal here I see that the destructor of my_worker is called**
}
But I dont want to emit the signal here and I want to destruct my_work when my My_Application is finished.
So in My_Application destructor I try to delete my_worker so the destructor is
My_Application::~My_Application(){
cout<<"the destructor called for app"<<endl;
if(my_worker->thread())
connect(my_worker,SIGNAL(destroyed()),my_thread,SLOT(quit()));
my_worker->deleteLater(); // this does not work and does not call my_worker destc.
}
Perhaps this might solve your problem:
class My_worker :public QObject, public QRunnable{
Q_OBJECT
public:
My_Worker() : loop(0) {}
void run();
public slots:
void sendData();
void quit();
private:
QEventLoop *loop;
};
My_Worker.cpp
void My_Worker::run(){
QTimer timer;
timer.setInterval(time_ms);
connect(&timer, SIGNAL(timeout()), this, SLOT(sendData()));
loop = new QEventLoop;
loop->exec();
delete loop;
}
void My_Worker::quit(){
if (loop){
loop->quit();
}
}
My_Application.cpp
My_Application::My_Application(){
My_worker *my_worker=new My_worker();
connect(this, SIGNAL(aboutToQuit()), my_worker, SLOT(quit()));
QThreadPool::globalInstance()->start(my_worker);
}
See the documentation for further information about the QThreadPool, QEventLoop and QRunnable classes.

Create Thread in QDialog and emit signals to QDialog in Qt

I created an application that has a mainwindow and from this window creates a QDialog. This QDialog should create a RenderThread that emits received images from the camera or in the example emits text. When i debug this it seems that the connection is never made as adding a breakpoint in the slot CameraWindow::debugSomething does not get caught. Whats wrong ?
I followed this example: http://qt-project.org/doc/qt-4.8/threads-mandelbrot.html but it seems that i've done something wrong.
qtDEVC::qtDEVC(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
connect (ui.pushButton_startCam, SIGNAL( clicked() ),this,SLOT( startCam() ) );
/**Threading*/
CameraWindow camWindow = new CameraWindow(this);
}
int qtDEVC::startCam()
{
camWindow.show();
camWindow.startCaptureThread();
}
CameraWindow Class:
CameraWindow::CameraWindow(QWidget *parent)
: QDialog(parent)
{
ui.setupUi(this);
connect(&thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
}
void CameraWindow::debugSomething(std::string something){
QString somethings(something.c_str());
qDebug()<<somethings;
}
int CameraWindow::startCaptureThread(){
RenderThread *thread = new RenderThread(this, guid, CLEYE_COLOR_RAW, CLEYE_VGA, 50);
thread->StartCapture(); //starts thread in low priority and sets _running to true
}
CameraWindow header
class CameraWindow : public QDialog
{
Q_OBJECT
public:
CameraWindow(QWidget *parent = 0);
~CameraWindow();
Ui::CameraWindow ui;
public slots:
int startCaptureThread();
void debugSomething(QString);
private:
RenderThread thread;
};
RenderThread Class
void RenderThread::run()
{
// image capturing loop
while(_running)
{
qDebug()<<("render while()"); //is printed with qdebug correctly
if (restart)
break;
if (abort)
return;
qDebug("it"); //is also printed with qdebug correctly
emit sendText(text);
}
RenderThread header
class RenderThread : public QThread
{
Q_OBJECT
public:
RenderThread(QObject *parent, GUID cameraGUID, CLEyeCameraColorMode mode, CLEyeCameraResolution resolution, float fps);
RenderThread();
~RenderThread();
bool StartCapture();
signals:
void sendText(QString &text);
protected:
void run();
private:
QMutex mutex;
QWaitCondition condition;
//some more private variables for construction
};
I think that this creation seems somehow wrong: RenderThread *thread = new RenderThread(this);
The first thing that's worrying about the question is the word "RenderThread". Note that Qt only allows rendering on the main thread. You can create separate threads for calculations of image data, but whenever you use a painter and draw objects, that must happen on the main thread. However, If you're just going to capture the image and pass that to the main thread, via signals and slots, then that should be ok.
Secondly, whilst you've not shown all your code, I'm assuming from the function called RenderThread::run() and from the Qt example that you may have inherited from QThread here. If this is the case, please note that this is not how to use QThread. Instead, you should have your class inherit from QObject and move that to a QThread. You can read about how to use QThread properly here.
I know it's a Qt example that you've followed, but even the guys at Qt think it's a bad idea. Here's an article of how to really use QThreads.
With that in mind, here's an outline of how I would use QThread for this: -
class CameraWindow : public QDialog
{
private:
CameraObject* m_pCamObject;
};
class CameraObject : public QObject
{
Q_OBJECT
public:
private slots:
startCaptureThread();
private:
};
int CameraWindow::startCaptureThread()
{
m_pCamObject = new CameraObject;
QThread* pThread = new QThread;
this->moveToThread(pThread); // CameraObject will run on the new thread
connect(pThread, SIGNAL(started()), m_pCamObject, SLOT(startCaptureThread()));
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()); // clear up when
finished
pThread->start();
}
Note that here is a CameraObject, separated from the CameraWindow. The QThread is just a controller of the thread and keeps a clean separation from the CameraObject.
Another reason for handling threads this way is that you can move multiple QObject instances to the new thread, rather than always creating a new thread per object. If you've more threads than CPU cores, you're unlikely to gain by creating yet another thread.
In the constructor of CameraWindow class, you are connecting a RenderThread's signal but it is not the same object which is started in startCaptureThread. Change your startCaptureThread like this:
int CameraWindow::startCaptureThread()
{
thread.StartCapture(); //starts thread in low priority and sets _running to true
}
In this method, the thread member of CameraWindow is started.
P.S.: post the headers too, we can't see the members from this code.
In the mentioned example, CameraWindow class holds a RenderThread thread variable, not a RenderThread *thread.
You are connecting a pointer address in your connect call:
connect(&thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
Try to use a good address:
connect(thread, SIGNAL(sendText(std::string)),
this, SLOT(debugSomething(std::string)));
This is not a tested answer.

QThread related problems

I'm having some problems and questions about QThread.
1) When I use QThread->quit(), finished() signal is not emitted..
2) How is right way to build and finish execution of thread?
1) finished signal code - the header file.
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
class MyThread: public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
signals:
public slots:
void finished();
protected:
void run();
};
#endif // MYTHREAD_H
1) CPP file.
#include "MyThread.h"
MyThread::MyThread(QObject *parent) :
QThread(parent)
{
}
void MyThread::finished()
{
//never gets called...
qDebug() << "Finished.";
}
void MyThread::run()
{
connect(this, SIGNAL(finished()), this, SLOT(finished()), Qt::DirectConnection);
this->exec();
}
I'm building it with this:
MyThread *mThread = new MyThread(this); //What does parent do/mean ?
mThread->start();
Sleep(5000); //Windows.
mThread->quit(); //Finish thread.
I even don't understand what Qt::DirectConnection does, I already read documentation, but I don't really get it how and when to use Direct/Queued connections.
Another questions that came to my mind just now.
1) How can I finish and cleanup thread from self? (I mean, thread should quit by itself and do cleanup.)
2) How to proper why of creating/running new thread and why?
Thank you.
Don't sub-class QThread. Instead, create a worker object (that inherits QObject), create a QThread, then call the moveToThread() method on your worker object.
class Worker : public QObject
{
Q_OBJECT
public:
Worker( QObject * parent = 0 )
: QObject( parent )
{
connect( this, SIGNAL(done()), \
this, SLOT(deleteLater())
);
}
public slots:
void doWork() { // work, work }
signals:
void done(); // emit this when you're finished with the work
};
// in your main function (or wherever)
QThread * thread = new QThread();
Worker * w = new Worker();
w->moveToThread( thread );
thread->start();
// clean up your thread
QObject::connect( w, SIGNAL(destroyed()), thread, SLOT(quit()) );
QObject::connect( thread, SIGNAL(finished()), thread(deleteLater()) );
// at some point, emit a signal connected to your workers 'doWork()' slot.
// when the work is finished, the worker and thread will both clean themselves up.
Edit: What if I'm using an older version of Qt?
In recent Qt releases, the default implementation of the QThread::run() method is to call exec(), which starts the thread's event loop. If you're supporting an older version of Qt, you do need to subclass QThread in order for the above code to work.
class MyThread : public QThread
{
void run() { exec(); }
};
Then, just use MyThread instead of QThread, and all of the above still applies. In this case, it makes perfect sense to subclass QThread because you're creating a specialized thread class (one that runs its own event loop when you call start()).
As for thread clean-up, the above still applies.
QObject::connect( thread, SIGNAL(finished()), thread, SLOT(deleteLater()) );
When you call MyThread::quit(), the event loop will return, run() will return, then the thread object emits the finished() signal. Since the MyThread object actually lives in the main event loop, the deleteLater() slot invocation will still be delivered.