I'm writing a simple Qt program to capture video feed from camera (using OpenCV). I'm using a QThread
object that loops, capturing images and feeding them to the MainWindow
object. This is working as it should.
The problem is that when I close, the application (i.e. pressing the "X") the camera capturing thread stops and the gui disappears. But the program is still running in the background. I also get a warning in the application output saying :
QThread: Destroyed while thread is still running.
How can I stop the application completely when quitting it?
main.cpp
#include <QApplication>
#include "application.h"
using namespace cv;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Application app;
app.init();
return a.exec();
}
application.h
#include "mainwindow.h"
#include "camerathread.h"
#include "mathandler.h"
#include "tools.h"
#include "opencv2/core/core.hpp"
#ifndef APPLICATION
#define APPLICATION
class Application : public MatHandler{
MainWindow w;
CameraThread ct;
public:
Application() {
w.setFixedSize(800,600);
}
void init() {
ct.setMatHandler(this);
ct.start();
w.show();
}
void handleMat(cv::Mat mat) {
QImage qImage = toQImage(mat);
w.setImage(qImage);
}
};
#endif // APPLICATION
camerathread
#include <QThread>
#include "mathandler.h"
#include "opencv2/highgui/highgui.hpp"
#ifndef CAMERATHREAD
#define CAMERATHREAD
class CameraThread : public QThread {
MatHandler *matHandler;
public:
~CameraThread() {
}
void setMatHandler(MatHandler *h) {
matHandler = h;
}
private: void run() {
cv::VideoCapture vc(0);
if (vc.isOpened()) {
for(;;) {
cv::Mat img;
vc >> img;
matHandler->handleMat(img);
}
}
}
};
#endif // CAMERATHREAD
The program consists of more code than this, but I only included the code I think is relevant for the question. I'll post the rest if necessary.
There are some major problems with your code. First of all in your run function the unending for loop will cause your thread to never stop unless you manage thread termination by your self like :
while(!finishThread)
{
cv::Mat img;
vc >> img;
matHandler->handleMat(img);
}
You should set finishThread
to true
when the application is going to close. Just provide a slot in which you set the value for finishThread
. When you want to terminate the thread emit a signal that is connected to that slot with a true
value. After that wait for the thread to finish properly for some seconds and force it to terminate if it did not finish :
emit setThreadFinished(true); //Tell the thread to finish
if(!ct->wait(3000)) //Wait until it actually has terminated (max. 3 sec)
{
ct->terminate(); //Thread didn't exit in time, probably deadlocked, terminate it!
ct->wait(); //We have to wait again here!
}
Also you should not directly call handleMat
function from an other thread. It may cause your application crash or lead to undefined behaviour. For that use signal/slot mechanism. Connect a signal from your thread to that slot and emit the signal along the argument each time you want to call it.
An other point is that you are better to derive your class from QObject
and use moveToThread
. You can do this in the constructor of your class:
th = new QThread();
this->setParent(0);
this->moveToThread(th);
QObject::connect(th,SIGNAL(started()),this,SLOT(OnStarted()));
QObject::connect(th,SIGNAL(finished()),this,SLOT(OnFinished()));
th->start();
Your initialization and termination tasks should be done in OnStarted()
and OnFinished()
slots respectively. You can have a worker function in which you run the repetitive operation.
Also in the destructor of your Application
class quit the thread in some way like the one stated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With