Я поймал closeEvent
от QMainWindow
в своем приложении, чтобы показать «Вы уверены?» всплывающее окно для пользователя, если он закрывает приложение с помощью кнопки «Х».
К сожалению, всплывающее окно создает проблемы, если приложение закрывается из самой Windows во время выключения.
Я хотел бы различать поведение, если приложение было закрыто с помощью кнопки «X» или самой ОС.
Является ли это возможным?
Я пытался использовать сигнал aboutToQuit
из Qt, но всплывающее окно появляется до того, как сигнал получен из моего приложения. Так что этот сигнал мне не помогает...
Вы можете использовать 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();
}
}
Проверял вашу идею на событии от bool QQuickWindow::event(QEvent *e)
. Но, к сожалению, мне это не помогает. Если я нажму на X
, я получу событие spontaneous
. Но если я выключу операционную систему, я также получу событие spontaneous
. Затем, поскольку всплывающее окно блокирует выключение системы, и я принудительно закрываю приложение, я получаю другое событие, и на этот раз это not spontaneous
... Любая подсказка/подсказка/идея, как решить проблему? Спасибо
В 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
}
}
Спасибо за Ваш ответ. Я надеялся, что есть что-то более простое, этот менеджер сеансов кажется более сложным в приложении, работающем на многих ОС.
Привет Базз. Спасибо за Ваш ответ. К сожалению, пока я его тестировал, я увидел, что мы также ловим
closing(QQuickCloseEvent*)
для QML. Это сигнал, который я получаю, ноQQuickCloseEvent
не является общедоступным, поэтому я не могу вызватьspotaneous()
, см.https://bugreports.qt.io/browse/QTBUG-36453
. У вас есть решение на случайQQuickCloseEvent
? Спасибо за вашу помощь