Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在注销时优雅地退出QApplication?_C++_Linux_Qt_Qt4_Qt5 - Fatal编程技术网

C++ 如何在注销时优雅地退出QApplication?

C++ 如何在注销时优雅地退出QApplication?,c++,linux,qt,qt4,qt5,C++,Linux,Qt,Qt4,Qt5,我有一个带有通知区域图标的应用程序,因此主窗口可能会忽略关闭事件。我正在尝试保存应用程序退出时的首选项和历史记录。我还想在应用程序运行时处理注销。虽然应用程序是跨平台的,但它在GNU/Linux中最方便/有用,因此Windows注销行为就不那么重要了。 这是一个最小的可编译示例,用于测试不同桌面环境/窗口管理器的行为: // main.cpp # include <QApplication> # include <QMainWindow> # include <QC

我有一个带有通知区域图标的应用程序,因此主窗口可能会忽略关闭事件。我正在尝试保存应用程序退出时的首选项和历史记录。我还想在应用程序运行时处理注销。虽然应用程序是跨平台的,但它在GNU/Linux中最方便/有用,因此Windows注销行为就不那么重要了。 这是一个最小的可编译示例,用于测试不同桌面环境/窗口管理器的行为:

// 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()
所有其他人都不会取消退出,但其中一些人会尝试警告应用程序

  • 我不知道日志中为什么会出现onAboutToQuit(),但是M::~M()在本例中不存在

    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:大胆,洋泾浜
    我检查了基于Qt的源代码,发现在处理closeEvent时没有什么特别之处:

    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 );
        }
    }