Search code examples
iconspyqt4tray

PyQt4 Tray Icon Problem when showing QLabel


When the following code runs, the tray application can pop-up the AboutWindow QLabel object in the middle of screen. But when closing this screen, the whole application is shutdown with no errors (the tray icon disappears and the console log shows no error whatsoever).

import sys
from PyQt4 import QtGui, QtCore


class AboutWindow(QtGui.QLabel):

def __init__(self, parent=None):
    QtGui.QLabel.__init__(self, parent=parent)
    self.setText("""
    Huge text goes here
    """)


class SystemTrayIcon(QtGui.QSystemTrayIcon):
    def __init__(self, icon, parent=None):
        QtGui.QSystemTrayIcon.__init__(self, icon, parent)
        menu = QtGui.QMenu(parent)
        self.createMenuActions(menu)
        self.setContextMenu(menu)
        # I've tried using the same parent as QSystemTrayIcon, 
        # but the label is not shown.
        # self.aboutWindow = AboutWindow(parent=parent)
        self.aboutWindow = AboutWindow(parent=None)


    def createMenuActions(self, menu):
        exitAction = QtGui.QAction("Exit", menu)
        configureAppAction = QtGui.QAction("Configure Application", menu)
        aboutAction = QtGui.QAction("About", menu)

        self.connect(configureAppAction, QtCore.SIGNAL('triggered()'), self._configureApp)
        self.connect(aboutAction, QtCore.SIGNAL('triggered()'), self._showAbout)
        self.connect(exitAction, QtCore.SIGNAL('triggered()'), self._exitApp)

        self.addActionsToMenu(menu, configureAppAction, aboutAction, exitAction)

    def addActionsToMenu(self, menu, *args):
        for action in args:
            menu.addAction(action)

    def _configureApp(self): pass

    def _showAbout(self):
        self.aboutWindow.show()

    def _exitApp(self):
        sys.exit(0)

def main():
    app = QtGui.QApplication(sys.argv)
    widget = QtGui.QWidget()
    # I'm passing a widget parent to QSystemTrayIcon as pointed out in:
    # http://stackoverflow.com/questions/893984/pyqt-show-menu-in-a-system-tray-application
    trayIcon = SystemTrayIcon(QtGui.QIcon("icon.xpm"), widget)
    trayIcon.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

As pointed out in the code, I've tried setting the same parent for the tray icon and the AboutWindow object, but that didn't work (the label is not shown). I have also tried subclassing QMainWindow, but the same effect occured.

I would like to understand if that's the default behavior when opening a new window from QSystemTrayIcon when neither the window and the icon share the same parent, and if there's a workaround for this matter.

Thanks.


Solution

  • Alright, I guess I wasn't too clear about the problem, but I found a simple solution.

    Qt has a method that captures the close event dispatched to a widget (http://doc.qt.nokia.com/4.6/qwidget.html#closeEvent). You can, in your QWidget subclass, rewrite this method to prevent the widget from closing (which, in all my tests, would close the whole application) and only hide it. The code below shows what I've changed in my code to make it work:

    ...
    
    class AboutWindow(QtGui.QLabel):
    
        def __init__(self, parent=None):
            QtGui.QLabel.__init__(self, parent=parent)
            self.setText("""
            Huge text goes here
            """)
    
        # Prevent the widget from closing the whole application, only hides it
        def closeEvent(self, event):
            event.ignore()
            self.hide()
    
    ...