我在我的应用程序中从
closeEvent
中捕捉到QMainWindow
,以显示“你确定吗?”弹出给用户,如果他用“X”按钮关闭应用程序。
不幸的是,如果应用程序在关机期间从 Windows 本身关闭,弹出窗口会产生问题。
如果使用“X”按钮或操作系统本身关闭应用程序,我想区分行为。
可能吗?
我尝试使用来自 Qt 的
aboutToQuit
信号,但弹出窗口出现在从我的应用程序接收到信号之前。所以这个信号对我没有帮助......
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();
}
}
在 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
}
}