C++ 如何在注销时优雅地退出QApplication?
我有一个带有通知区域图标的应用程序,因此主窗口可能会忽略关闭事件。我正在尝试保存应用程序退出时的首选项和历史记录。我还想在应用程序运行时处理注销。虽然应用程序是跨平台的,但它在GNU/Linux中最方便/有用,因此Windows注销行为就不那么重要了。 这是一个最小的可编译示例,用于测试不同桌面环境/窗口管理器的行为:C++ 如何在注销时优雅地退出QApplication?,c++,linux,qt,qt4,qt5,C++,Linux,Qt,Qt4,Qt5,我有一个带有通知区域图标的应用程序,因此主窗口可能会忽略关闭事件。我正在尝试保存应用程序退出时的首选项和历史记录。我还想在应用程序运行时处理注销。虽然应用程序是跨平台的,但它在GNU/Linux中最方便/有用,因此Windows注销行为就不那么重要了。 这是一个最小的可编译示例,用于测试不同桌面环境/窗口管理器的行为: // main.cpp # include <QApplication> # include <QMainWindow> # include <QC
// main.cpp
# include <QApplication>
# include <QMainWindow>
# include <QCloseEvent>
# include <QTimer>
# include <iostream>
class M : public QMainWindow
{
Q_OBJECT
public:
~M();
public slots:
void onAboutToQuit();
private:
void closeEvent(QCloseEvent *);
};
M::~M()
{
std::cout << "M::~M()" << std::endl;
}
void M::onAboutToQuit()
{
std::cout << "onAboutToQuit()" << std::endl;
}
void M::closeEvent(QCloseEvent * e)
{
std::cout << "closeEvent()" << std::endl;
hide();
QTimer::singleShot(5000, this, SLOT(show()));
e->ignore();
}
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
M m;
m.setWindowModality(Qt::NonModal);
m.connect(& app, SIGNAL(aboutToQuit()),
SLOT(onAboutToQuit()));
m.show();
return app.exec();
}
# include "main.moc"
// CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(closeeventbug)
option(QT5 "Use Qt5" OFF)
if(QT5)
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
else()
find_package(Qt4 REQUIRED)
include_directories(${QT_INCLUDES})
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_AUTOMOC ON)
add_executable(closeeventbug main.cpp)
if(QT5)
qt5_use_modules(closeeventbug Core Widgets)
else()
target_link_libraries(closeeventbug ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
endif()
所有其他人都不会取消退出,但其中一些人会尝试警告应用程序
closeEvent()
onAboutToQuit()
{ Windows7 }
{RazorQt、LxDE、LxQt、i3、budgie、fluxbox、Aweasome、openbox、,
wmii、E16、pekWM、uwm、fvwm、xmonad、spectrwm、windowmaker、,
herbstluftwm,WindowsXP}
对于(GCC 4.9.1或Clang 3.4.2)和(Qt 4.8.6或Qt 5.3.1)的任何组合,行为完全相同。但是,当我在Xubuntu上尝试Qt4.8和Qt5.2时,结果有些不同:在XFCE中Qt5.2没有阻塞-无论主窗口的可见性如何,应用程序都会顺利完成。但是Qt4.8出现了阻塞(与Manjaro相同)
我知道可以正确地处理注销(无阻塞),因为有几个应用程序可以做到这一点。它们都有通知区图标,关闭通知区,但不阻止注销
- 基于Qt的:GoldenDict、Transmission Qt、Kopete李>
- 基于GTK:大胆,洋泾浜
https://github.com/goldendict/goldendict/blob/master/mainwindow.cc
void MainWindow::closeEvent( QCloseEvent * ev )
{
if ( cfg.preferences.enableTrayIcon && cfg.preferences.closeToTray )
{
ev->ignore();
hide();
}
else
{
ev->accept();
qApp->quit();
}
}
https://github.com/bfleischer/transmission/blob/master/qt/mainwin.cc
void
TrMainWindow :: closeEvent( QCloseEvent * event )
{
// if they're using a tray icon, close to the tray
// instead of exiting
if( !myPrefs.getBool( Prefs :: SHOW_TRAY_ICON ) )
event->accept( );
else {
toggleWindows( false );
event->ignore( );
}
}
void
TrMainWindow :: toggleWindows( bool doShow )
{
if( !doShow )
{
hide( );
}
else
{
if ( !isVisible( ) ) show( );
if ( isMinimized( ) ) showNormal( );
//activateWindow( );
raise( );
QApplication::setActiveWindow( this );
}
}
git clone git://anongit.kde.org/kopete
void KopeteWindow::closeEvent ( QCloseEvent *e )
{
// if we are not ok to exit on close and we are not shutting down then just do what needs to be done if a
// window is closed.
KopeteApplication *app = static_cast<KopeteApplication *> ( kapp );
if ( !shouldExitOnClose() && !app->isShuttingDown() && !app->sessionSaving() ) {
// BEGIN of code borrowed from KMainWindow::closeEvent
// Save settings if auto-save is enabled, and settings have changed
if ( settingsDirty() && autoSaveSettings() )
saveAutoSaveSettings();
if ( queryClose() ) {
e->accept();
}
// END of code borrowed from KMainWindow::closeEvent
kDebug ( 14000 ) << "just closing because we have a system tray icon";
}
else
{
kDebug ( 14000 ) << "delegating to KXmlGuiWindow::closeEvent()";
KXmlGuiWindow::closeEvent ( e );
}
}
https://github.com/goldendict/goldendict/blob/master/mainwindow.cc
void主窗口::关闭事件(QCloseEvent*ev)
{
if(cfg.preferences.enableTrayIcon&&cfg.preferences.closeToTray)
{
ev->ignore();
隐藏();
}
其他的
{
ev->accept();
qApp->quit();
}
}
https://github.com/bfleischer/transmission/blob/master/qt/mainwin.cc
无效的
TrMainWindow::closeEvent(QCloseEvent*事件)
{
//如果他们使用的是托盘图标,请靠近托盘
//而不是退出
如果(!myPrefs.getBool(Prefs::SHOW_托盘图标))
事件->接受();
否则{
切换窗口(假);
事件->忽略();
}
}
无效的
TrMainWindow::切换窗口(bool doShow)
{
如果(!doShow)
{
隐藏();
}
其他的
{
如果(!isVisible())show();
if(isMinimized())showNormal();
//激活窗口();
提高();
QApplication::setActiveWindow(此);
}
}
git克隆git://anongit.kde.org/kopete
void KopeteWindow::closeEvent(QCloseEvent*e)
{
//如果我们不能在关闭时退出,并且我们没有关闭,那么只需在出现故障时执行需要执行的操作即可
//窗户关上了。
KopeteApplication*app=静态施法(kapp);
如果(!shouldExitOnClose()&&!app->isShuttingDown()&&&!app->sessionSaving()){
//从KMainWindow::closeEvent借用的代码的开头
//如果启用了自动保存且设置已更改,则保存设置
if(setingsdirty()&&autoSaveSettings())
保存自动保存设置();
if(queryClose()){
e->accept();
}
//从KMainWindow::closeEvent借用的代码结束
kDebug(14000)QApplication与操作系统会话操作相关-您可以轻松处理它。有关更多详细信息,请参阅Qt文档页面您为我指明了正确的方向。非常感谢。但是,GoldenDict和Kopete都使用-我相信它更适合我的情况。并且(至少对于KDE中的GoldenDict)似乎commitData()就足够了,因为会话恢复时窗口恢复得很好。所以我将使用or。让我别无选择-为了同时支持Qt4和Qt5(5.2或更高版本!),我必须使用。
closeEvent()
{ icewm, E17 }
<nothing in the log>
{ RazorQt, LxDE, LxQt, i3, budgie, fluxbox, awesome, openbox,
wmii, E16, pekWM, uwm, fvwm, xmonad, spectrwm, windowmaker,
herbstluftwm, WindowsXP }
https://github.com/goldendict/goldendict/blob/master/mainwindow.cc
void MainWindow::closeEvent( QCloseEvent * ev )
{
if ( cfg.preferences.enableTrayIcon && cfg.preferences.closeToTray )
{
ev->ignore();
hide();
}
else
{
ev->accept();
qApp->quit();
}
}
https://github.com/bfleischer/transmission/blob/master/qt/mainwin.cc
void
TrMainWindow :: closeEvent( QCloseEvent * event )
{
// if they're using a tray icon, close to the tray
// instead of exiting
if( !myPrefs.getBool( Prefs :: SHOW_TRAY_ICON ) )
event->accept( );
else {
toggleWindows( false );
event->ignore( );
}
}
void
TrMainWindow :: toggleWindows( bool doShow )
{
if( !doShow )
{
hide( );
}
else
{
if ( !isVisible( ) ) show( );
if ( isMinimized( ) ) showNormal( );
//activateWindow( );
raise( );
QApplication::setActiveWindow( this );
}
}
git clone git://anongit.kde.org/kopete
void KopeteWindow::closeEvent ( QCloseEvent *e )
{
// if we are not ok to exit on close and we are not shutting down then just do what needs to be done if a
// window is closed.
KopeteApplication *app = static_cast<KopeteApplication *> ( kapp );
if ( !shouldExitOnClose() && !app->isShuttingDown() && !app->sessionSaving() ) {
// BEGIN of code borrowed from KMainWindow::closeEvent
// Save settings if auto-save is enabled, and settings have changed
if ( settingsDirty() && autoSaveSettings() )
saveAutoSaveSettings();
if ( queryClose() ) {
e->accept();
}
// END of code borrowed from KMainWindow::closeEvent
kDebug ( 14000 ) << "just closing because we have a system tray icon";
}
else
{
kDebug ( 14000 ) << "delegating to KXmlGuiWindow::closeEvent()";
KXmlGuiWindow::closeEvent ( e );
}
}