使用 Qt 将关闭事件与“X”按钮和操作系统关闭区分开来

问题描述 投票:0回答:2

我在我的应用程序中从

closeEvent
中捕捉到
QMainWindow
,以显示“你确定吗?”弹出给用户,如果他用“X”按钮关闭应用程序。

不幸的是,如果应用程序在关机期间从 Windows 本身关闭,弹出窗口会产生问题。

如果使用“X”按钮或操作系统本身关闭应用程序,我想区分行为。

可能吗?

我尝试使用来自 Qt 的

aboutToQuit
信号,但弹出窗口出现在从我的应用程序接收到信号之前。所以这个信号对我没有帮助......

windows qt qt5 application-shutdown
2个回答
0
投票

您可以使用

QEvent::spontaneous()
辨别
X
按钮被点击(
True
)或操作系统关闭。

注意:从任务管理器关闭进程会使布尔值变为真,但无论如何都会强制关闭进程(很明显,正如预期的那样)

在 Windows 11 上测试:


void MainWindow::closeEvent(QCloseEvent *event)
{
    qDebug() << "Spontaneous: " << event->spontaneous();
    if (event->spontaneous())
    {
        // X button clicked
        auto res = QMessageBox::question(this, "Sure?", "Sure you want to exit?", QMessageBox::Yes | QMessageBox::No);
        if (res == QMessageBox::Yes)
            event->accept();
        else
            event->ignore();
    }
    else {
        event->accept();
    }

}

0
投票

在 Windows 中,启动关闭时会向所有窗口发送两条消息:

WM_QUERYENDSESSION
WM_ENDSESSION
,它们被转换为
QtWindows::QueryEndSessionApplicationEvent
QtWindows::EndSessionApplicationEvent
。此事件在
QWindowsContext::windowsProc
中处理:第一个在应用程序实例上调用
QApplication::commitData
,它从会话管理器实例发出
commitDataRequest()
,第二个从应用程序实例发出
aboutToQuit()

Qt 的相关部分称为 Session Management,包括一组特定于平台的 QSessionManager 类。以下是文档推荐的内容:

首先将插槽连接到 QGuiApplication::commitDataRequest() 信号,使您的应用程序能够参与优雅的注销过程。如果您只针对 Microsoft Windows 平台,那么这就是您可以而且必须提供的全部内容。理想情况下,您的应用程序应该提供一个关闭对话框。

这是文档中的示例,您可以如何执行此操作:

MyMainWidget::MyMainWidget(QWidget *parent)
    :QWidget(parent)
{
    QGuiApplication::setFallbackSessionManagementEnabled(false);
    connect(qApp, &QGuiApplication::commitDataRequest,
            this, &MyMainWidget::commitData);
}

void MyMainWidget::commitData(QSessionManager& manager)
{
    if (manager.allowsInteraction()) {
        int ret = QMessageBox::warning(
                    mainWindow,
                    tr("My Application"),
                    tr("Save changes to document?"),
                    QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);

        switch (ret) {
        case QMessageBox::Save:
            manager.release();
            if (!saveDocument())
                manager.cancel();
            break;
        case QMessageBox::Discard:
            break;
        case QMessageBox::Cancel:
        default:
            manager.cancel();
        }
    } else {
        // we did not get permission to interact, then
        // do something reasonable instead
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.