pythonmenupyqtsystem-tray

PyQt: Show menu in a system tray application


First of all, I'm an experienced C programmer but new to python. I want to create a simple application in python using pyqt. Let's imagine this application it is as simple as when it is run it has to put an icon in the system tray and it has offer an option in its menu to exit the application.

This code works, it shows the menu (I don't connect the exit action and so on to keep it simple)

import sys
from PyQt4 import QtGui

def main():
    app = QtGui.QApplication(sys.argv)

    trayIcon = QtGui.QSystemTrayIcon(QtGui.QIcon("Bomb.xpm"), app)
    menu = QtGui.QMenu()
    exitAction = menu.addAction("Exit")
    trayIcon.setContextMenu(menu)

    trayIcon.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

But this doesn't:

import sys
from PyQt4 import QtGui

class SystemTrayIcon(QtGui.QSystemTrayIcon):

    def __init__(self, icon, parent=None):
        QtGui.QSystemTrayIcon.__init__(self, icon, parent)
        menu = QtGui.QMenu()
        exitAction = menu.addAction("Exit")
        self.setContextMenu(menu)

def main():
    app = QtGui.QApplication(sys.argv)

    trayIcon = SystemTrayIcon(QtGui.QIcon("Bomb.xpm"), app)

    trayIcon.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

I probably miss something. There are no errors but in the second case when I click with the right button it doesn't show the menu.


Solution

  • Well, after some debugging I found the problem. The QMenu object it is destroyed after finish __init__ function because it doesn't have a parent. While the parent of a QSystemTrayIcon can be an object for the QMenu it has to be a Qwidget. This code works (see how QMenu gets the same parent as the QSystemTrayIcon which is an QWidget):

    import sys
    from PyQt4 import QtGui
    
    class SystemTrayIcon(QtGui.QSystemTrayIcon):
    
        def __init__(self, icon, parent=None):
            QtGui.QSystemTrayIcon.__init__(self, icon, parent)
            menu = QtGui.QMenu(parent)
            exitAction = menu.addAction("Exit")
            self.setContextMenu(menu)
    
    def main():
        app = QtGui.QApplication(sys.argv)
    
        w = QtGui.QWidget()
        trayIcon = SystemTrayIcon(QtGui.QIcon("Bomb.xpm"), w)
    
        trayIcon.show()
        sys.exit(app.exec_())
    
    if __name__ == '__main__':
        main()