我正在编写一个简单的Qt程序来捕获来自摄像头的视频(使用OpenCV)。我正在使用一个QThread
对象循环,捕获图像并将它们提供给MainWindow
对象。这是应该的。
问题是,当我关闭时,应用程序(即按下“X”)摄像机捕获线程停止并且gui消失。但该程序仍在后台运行。我还在应用程序输出中收到警告:
QThread:线程仍在运行时被破坏。
退出时如何完全停止应用程序?
的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
该程序包含的代码多于此,但我只包含了我认为与该问题相关的代码。如果有必要,我会发布其余的内容。
答案 0 :(得分:3)
您的代码存在一些主要问题。首先在你的run函数中,无限循环将导致你的线程永远不会停止,除非你自己管理线程终止,如:
while(!finishThread)
{
cv::Mat img;
vc >> img;
matHandler->handleMat(img);
}
应用程序即将关闭时,您应将finishThread
设置为true
。只需提供一个插槽,您可以在其中设置finishThread
的值。当您想要终止线程时,发出一个连接到该槽的信号,其值为true
。之后等待线程正常完成几秒钟并强制它终止,如果它没有完成:
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!
}
此外,您不应该直接从其他线程调用handleMat
函数。它可能会导致您的应用程序崩溃或导致未定义的行为。对于那个使用信号/插槽机制。将线程中的信号连接到该插槽,并在每次调用时沿参数发出信号。
另一点是,您最好从QObject
派生您的课程并使用moveToThread
。您可以在类的构造函数中执行此操作:
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();
您的初始化和终止任务应分别在OnStarted()
和OnFinished()
个插槽中完成。您可以使用worker函数来运行重复操作。
同样在你的Application
类的析构函数中,以某种方式退出该线程。