天天看点

qt最小化托盘失焦问题

qt通过QSystemTrayIcon很容易实现最小化托盘,但本人使用过程中发现一些特殊情况下的问题:

[1]qt4.8版本,在win及redhat6.5/5.5的32bit或64系统中静态编译的qt,在实现最小化托盘功能时

1)如果你的托盘菜单除了启动主窗体外,还能启动其它窗体

2)当主窗体最小化后,如果从托盘菜单进入其它窗体,这时焦点会跳转到该窗体

3)如果你主窗体处于最小化状态时,关闭了当前窗体,qt程序会捕捉不到焦点而退出程序

[2]qt4.8版本,在国产麒麟系统64位中,静态编译了qt,实现最小化托盘功能时

1)程序启动后,没有托盘显示,

2)当点击最小化托盘时,程序直接隐藏,也没有托盘出现

3)在进程查看中发现变成了僵死进程

示例解析:

void MainWindow::initTray()

{

    Qt::WindowFlags flags = 0;

    flags |= Qt::WindowMinMaxButtonsHint;

    flags |= Qt::CustomizeWindowHint;

    this->setWindowFlags(flags);

    this->setMouseTracking(true);

    QIcon icon = QIcon(":/images/iconApp.png");

    trayIcon = new QSystemTrayIcon(this);

    trayIcon->setIcon(icon);

    trayIcon->setToolTip(tr("ET1100-Browse"));

    QString titlec=tr("ET1100-Evt");

    QString textc=tr("app manage interface");

    trayIcon->show();

    trayIcon->showMessage(titlec,textc,QSystemTrayIcon::Information,5000);

    //添加单/双击鼠标相应

    connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),

            this,SLOT(trayiconActivated(QSystemTrayIcon::ActivationReason)));

    //创建行为

    minimizeAction = new QAction(tr("Min(&I)"), this);

    connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));

    restoreAction = new QAction(tr("Rec(&R)"), this);

    connect(restoreAction, SIGNAL(triggered()), this, SLOT(showMaximized()));

    helpAction = new QAction(tr("Help(&H)"), this);//帮助窗体,会开启帮助手册窗口

    connect(helpAction, SIGNAL(triggered()), this, SLOT(helpView()));

    quitAction = new QAction(tr("Quit(&Q)"), this);

    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));

    //创建右键弹出菜单

    trayIconMenu = new QMenu((QWidget*)QApplication::desktop());

    trayIconMenu->addAction(minimizeAction);

    trayIconMenu->addAction(restoreAction);

    trayIconMenu->addAction(helpAction);

    trayIconMenu->addSeparator();

    trayIconMenu->addAction(quitAction);

    trayIcon->setContextMenu(trayIconMenu);

}

void MainWindow::trayiconActivated(QSystemTrayIcon::ActivationReason reason)

    switch (reason)

    {

    case QSystemTrayIcon::Trigger:

        //单击托盘图标

    case QSystemTrayIcon::DoubleClick:

        //双击托盘图标

        this->showMaximized();

        this->raise();

        break;

    default:

    }

void MainView::changeEvent ( QEvent * event )

     //重点,窗口最小化时隐藏窗口,最小化到托盘   

    if(event->type()==QEvent::WindowStateChange)  

    {  

        //changeEvent会在窗口最小化之前调用,如果不加QTimer,   

        //我们把窗口隐藏了,但是Qt还以为窗口正要最小化,这样就会出错   

        if(windowState() & Qt::WindowMinimized){

            QTimer::singleShot(0, this, SLOT(hide()));

        }

    }  

    QWidget::changeEvent(event);  

在创建托盘菜单时,加入了一个帮助手册实现的窗体响应,可以在托盘菜单右键启动帮助窗体,窗体的启动及关闭实现函数:

void MainWindow::helpView()

    if (NULL!=assistant)

    {

        return;

    }

    //

    assistant = new Assistant("User-Manual.html");

    assistant->setMinimumSize(800, 600);

    connect(assistant,SIGNAL(closeNotify()),this,SLOT(closeHelpView()));

    assistant->show();

void MainWindow::closeHelpView()

    this->showMaximized();//激活主窗体防止失去焦点被qt内部退出

    this->raise();

    assistant->close();

    delete assistant;

    assistant=NULL;

在样例中是采用最简单的重新把已最小化的主窗体显示来获取焦点防止被退出,

如果没有这一步骤,在主窗体隐藏时关闭其它窗体会程序退出,,这样勉强内解决问题[1]

问题[2]是直接主窗体最小化及程序当掉,并残留在进程中

感觉无论是问题[1]还是问题[2],在调试时,没有捕捉到任何因为关闭其它窗体[1]或隐藏主窗体[2]引起qapp的关闭事件。

将this->showMaximized();注释掉,发现qt内部在处理事件时捕捉不到焦点进行主动关闭处理,,查看内部调用,

当其它窗体激活时,

        // then focus events

        if (!QApplicationPrivate::active_window && QApplicationPrivate::focus_widget) {

            QApplicationPrivate::setFocusWidget(0, Qt::ActiveWindowFocusReason);

        } else if (QApplicationPrivate::active_window) {

            QWidget *w = QApplicationPrivate::active_window->focusWidget();

            if (w && w->isVisible() /*&& w->focusPolicy() != QWidget::NoFocus*/)

                w->setFocus(Qt::ActiveWindowFocusReason);

            else {

                w = QApplicationPrivate::focusNextPrevChild_helper(QApplicationPrivate::active_window, true);

                if (w) {

                    w->setFocus(Qt::ActiveWindowFocusReason);

                } else {

                    // If the focus widget is not in the activate_window, clear the focus

                    w = QApplicationPrivate::focus_widget;

                    if (!w && QApplicationPrivate::active_window->focusPolicy() != Qt::NoFocus)

                        QApplicationPrivate::setFocusWidget(QApplicationPrivate::active_window, Qt::ActiveWindowFocusReason);

                    else if (!QApplicationPrivate::active_window->isAncestorOf(w))

                        QApplicationPrivate::setFocusWidget(0, Qt::ActiveWindowFocusReason);

                }

            }

焦点将被设置其它窗体

但是当关闭焦点窗体(如HelpView)就直接调用了

void MainWindow::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)

......................................

case 3: _t->closeHelpView(); break;

.................................

激活了QApplication::~QApplication()退出程序。

因此,可以将其它窗体在主窗体进行调用激活,远离托盘菜单。

继续阅读