QApplication:如何在 Ctrl-C 上正常关机

Posted

技术标签:

【中文标题】QApplication:如何在 Ctrl-C 上正常关机【英文标题】:QApplication: How to shutdown gracefully on Ctrl-C 【发布时间】:2010-02-19 23:49:50 【问题描述】:

我有一个QApplication,根据命令行参数,它有时实际上没有 GUI 窗口,只是在没有 GUI 的情况下运行。在这种情况下,如果 CTRL-C 被击中,我想优雅地关闭它。基本上我的代码如下所示:

int main(int argc, char* argv[])

    QApplication app(argc, argv);

    ... // parse command line options

    if (no_gui) 
        QObject::connect(&app, SIGNAL(unixSignal(int)),
                         &app, SLOT(quit()));
        app.watchUnixSignal(SIGINT, true);
        app.watchUnixSignal(SIGTERM, true);
    

    ... 

    return app.exec();

但是,这不起作用。 CTRL-C 似乎被捕获(应用程序没有被杀死),但它也没有退出。我错过了什么?

【问题讨论】:

This is very well documented. Use the documentation. 【参考方案1】:

可能有一种方法可以使用 Qt 原生地做到这一点——我在放弃之前浏览了 QKeySequence 文档,但您可以使用 signal。目前我的机器上没有 Qt/C++ 设置,但我有 Python 绑定。

import sys, signal
from PyQt4 import QtGui

app = QtGui.QApplication(sys.argv)
signal.signal(signal.SIGINT, signal.SIG_DFL)

sys.exit(app.exec_())

这很有效,当我执行 Ctrl-C 时会关闭应用程序。所以我相信你的应用程序可以修改这段代码,最终会是这样的:

#include <signal.h>

int main(int argc, char* argv[])

    QApplication app(argc, argv);

    ... // parse command line options

    if (no_gui) 
        signal(SIGINT, SIG_DFL);
    

    ... 

    return app.exec();

不幸的是,我无法编译它,所以它可能需要一些修复,但这应该会给你一个大致的想法。通过使用SIG_DFL 处理程序,您可以指示您的程序使用与 Ctrl-C 关联的默认操作。

【讨论】:

【参考方案2】:

由于没有记录,因此不应使用 QApplication::watchUnixSignal。而且,通过阅读代码,在使用 glib 事件调度器(这是 Linux 上的默认设置)时,它将无法正常工作。

但是,一般而言,您可以在 Qt 应用程序中安全地捕获 Unix 信号,您只需自己编写一些代码即可。文档中甚至还有一个示例 - Calling Qt Functions From Unix Signal Handlers。

【讨论】:

由于没有办法在那个页面上评论,我只是在这里问一个简单的问题,希望对其他人有用:为什么初始化的一部分被分离成自己的静态方法“静态 int setup_unix_signal_handlers()”? 我没有看到 setup_unix_signal_handlers() 是静态的任何原因,它作为实例方法的一部分可以正常工作。文件描述符数组也可以是非静态的,但前提是您具有 C++11 或更高版本的初始化语法。【参考方案3】:

您可以使用 QApplication::instance()(或更短的宏版本 qApp),至少从 Qt4 开始都可以使用:

#include <QApplication>
#include <csignal>

void sigHandler(int s)

    std::signal(s, SIG_DFL);
    qApp->quit();


int main(int argc, char * argv[])

    QApplication app(argc, argv);

    std::signal(SIGINT,  sigHandler);
    std::signal(SIGTERM, sigHandler);

    return app.exec();

【讨论】:

更简单但功能强大的解决方案。【参考方案4】:

除了 Qt 4.0 的 one liner 之外,我没有找到更多关于 QApplication::watchUnixSignal 的文档;特别是在 Qt 的更高版本中没有记录。因此,看起来这个功能没有被宣传(因此应该)工作。虽然这样做“Qt 方式”显然很好,但我只是回退到使用 signal system call 代替。

【讨论】:

【参考方案5】:

正如 Jerkface Jones 所提到的,这看起来在 Linux 上使用默认事件处理程序不起作用。

如果 Qt 使用原始的 Unix(非 glib)事件处理程序,Qt 将在其信号处理程序中立即捕获并吸收 ^C,但在 Qt 进行事件处理之前不会发出 unixSignal(int) 信号.

如果您有代码正在运行(而不是在等待 Qt 发送信号),那么您需要调用 QApplication::processEvents() 让 Qt 发送信号。

【讨论】:

以上是关于QApplication:如何在 Ctrl-C 上正常关机的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 上注册 ACTION_VIEW Intent?为啥我的 QApplication 没有收到 QEvent::FileOpen 事件?

Ruby 命令行:如何通过命令行中的文本发送 CTRL-C 命令?

如何在 python 程序中关闭 Ctrl-C 上的套接字连接

如何在不使用 ctrl-c 的情况下停止烧瓶应用程序

如何在 C# 控制台应用程序中捕获 ctrl-c (SIGINT)

多个 QApplication 实例