如何从主窗体完全/正确退出 Qt 程序?

Posted

技术标签:

【中文标题】如何从主窗体完全/正确退出 Qt 程序?【英文标题】:How to fully/correctly exit a Qt program from the main form? 【发布时间】:2015-05-25 02:29:33 【问题描述】:

我正在编写一个 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 \n\n exiting program\n");
    QApplication::quit();


// process frame here . . .

这个想法是如果网络摄像头可以在程序开始时成功读取,但不能(网络摄像头停止工作,用户意外断开网络摄像头等),程序应该显示一个消息框,然后关闭完全是自己。

使用上述方法,如果我在程序运行时出于测试目的拔下网络摄像头,消息框会按预期显示,但在选择“确定”后,会出现调试错误屏幕。如果我选择“中止”,表格仍然存在并且不会响应。在尝试多次关闭窗体后,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 \n\n exiting program\n");
    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 程序提供进一步的建议吗?请指教。

【问题讨论】:

【参考方案1】:

有两件事可能解决您的问题:

    在显示 messagebox 之前,使用 stop() 方法停止计时器。 QApplication::quit(); 退出函数后 return; 您的函数可能最后一次运行到最后并访问无效对象。李>

【讨论】:

【参考方案2】:

供其他人参考,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 \n\n exiting program\n");
        closeEvent(new QCloseEvent());
        return;          // had to add return here !!!!!!!!!
    

    // rest of function here . . .

我应该提到我必须同时添加返回和停止计时器。谢谢拉斐尔!

【讨论】:

这看起来有点笨拙和丑陋。你不应该直接打电话给closeEvent。它是一个事件处理程序。相反,您应该致电QWidget::close。您也可以尝试使用QApplication::closeAllWindows 插槽。

以上是关于如何从主窗体完全/正确退出 Qt 程序?的主要内容,如果未能解决你的问题,请参考以下文章

QT 对话框的样式不正确

Qt:退出应用程序->正确清理的清单

qt creator源码全方面分析(2-10)

如何从主窗体更新子窗体中的图像框控件源

如何从主窗体内部引用子窗体中对象的事件

在退出之前跟踪 - 并正确结束 - C# - C++/CLI - C++ Windows 窗体应用程序中的本机和托管线程