我正在编写一个Qt程序(使用Qt 5.4),基于QTimer从网络摄像头读取帧,而不是一个单独的线程(间隔设置为20毫秒,当然它需要比1/50秒更长的时间从网络摄像头读取帧并处理它,我估计帧率可能是20 fps。无论如何,计时器循环时运行的函数是一个槽,如下所示:
///////////////////////////////////////////////////////////////////////////////////////////////////
void frmMain::processFrameAndUpdateGUI() {
bool blnFrameReadSuccessfully = capWebcam.read(matOriginal); // get next frame from the webcam
if (!blnFrameReadSuccessfully || matOriginal.empty()) { // if we did not get a frame
QMessageBox::information(this, "", "unable to read from webcam nn exiting programn");
QApplication::quit();
}
// process frame here . . .
这个想法是,如果在程序开始时可以成功读取网络摄像头,但随后无法读取(网络摄像头停止工作,用户不小心断开网络摄像头等),程序应该显示一个消息框,然后完全关闭自己。
在上面的情况下,如果我在程序运行时拔掉网络摄像头进行测试,消息框会按预期出现,但在选择OK后,会出现一个调试错误屏幕。如果我选择"中止",表单仍然在那里,不会响应。在多次尝试关闭窗体后,Windows询问"该程序似乎没有响应,您是否要关闭?"这时我可以关闭窗体。显然,这并没有达到预期的效果。
经过各种各样的谷歌搜索,我发现建议修改如下:
///////////////////////////////////////////////////////////////////////////////////////////////////
void frmMain::closeEvent(QCloseEvent *) {
QApplication::quit();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void frmMain::processFrameAndUpdateGUI() {
bool blnFrameReadSuccessfully = capWebcam.read(matOriginal); // get next frame from the webcam
if (!blnFrameReadSuccessfully || matOriginal.empty()) { // if we did not get a frame
QMessageBox::information(this, "", "unable to read from webcam nn exiting programn");
closeEvent(new QCloseEvent());
}
// process frame here . . .
当我第一次看到这段代码时,我很乐观,但是它给了我与上面相同的结果(程序挂起,窗体仍然打开)。我使用OpenCV 2.4.11进行图像处理,我的程序有4个文件:
- frmmain.h (.h为主窗体,它是用Qt Creator制作的标准QMainWindow)
- frmmain.cpp (.cpp为主表单,上面代码所在的位置)
- main.cpp(我没有改变Qt Creator的制作方式)
- frmmain。ui(通过Qt Creator添加少量常见小部件的典型表单)
是的,我意识到我可以在一个可以显示文本的小部件上显示错误消息,从函数返回,并让用户关闭程序,但我正在寻找一个更优雅的解决方案。谁能提供进一步的建议,如何完全关闭图形Qt程序?请建议。
有两件事可以解决你的问题:
- 在显示消息框之前,使用stop()方法停止计时器。
- 在QApplication::quit()之后;用return退出函数;你的函数可能最后一次运行到结束并且访问了无效的对象。
供其他人参考,Rafael Monteiro的回答是正确的。以下是更新后的代码(经过验证可以正常工作):
///////////////////////////////////////////////////////////////////////////////////////////////////
void frmMain::closeEvent(QCloseEvent *) {
if(qtimer->isActive()) qtimer->stop(); // had to stop timer here !!!!!!!!
QApplication::quit();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void frmMain::processFrameAndUpdateGUI() {
bool blnFrameReadSuccessfully = capWebcam.read(matOriginal); // get next frame from the webcam
if (!blnFrameReadSuccessfully || matOriginal.empty()) { // if we did not get a frame
QMessageBox::information(this, "", "unable to read from webcam nn exiting programn");
closeEvent(new QCloseEvent());
return; // had to add return here !!!!!!!!!
}
// rest of function here . . .
我应该提到我必须添加返回和停止计时器。谢谢拉斐尔!