0

I'm running python 3.9.7 on windows 10. Please consider the following code (note you will need icon.png to run)

from PyQt6.QtGui import QAction, QIcon
from PyQt6.QtWidgets import QSystemTrayIcon, QApplication, QMenu
  
  
app = QApplication([])
app.setQuitOnLastWindowClosed(False)

'''Create the system tray'''
tray = QSystemTrayIcon()
tray.setIcon(QIcon("icon.png"))
tray.show()
  
'''Add a menu with a quit action'''
menu = QMenu()
quit = QAction("Quit")
quit.triggered.connect(app.quit)
menu.addAction(quit)
'''Give the menu to the tray'''
tray.setContextMenu(menu)

'''Lets see where the menu is drawn'''
menu.aboutToShow.connect(lambda: print(menu.pos()))
  
app.exec()

The above works as expected on my system. However, when I subclass QSystemTrayIcon like so:

from PyQt6.QtGui import QAction, QIcon
from PyQt6.QtWidgets import QSystemTrayIcon, QApplication, QMenu

class SystemTrayIcon(QSystemTrayIcon):
    
    def __init__(self, icon: QIcon, app: QApplication, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        '''setup'''
        self.setIcon(icon)
        self.show()
        
        '''Add a menu with a quit action'''
        menu = QMenu()
        quit = QAction("Quit")
        quit.triggered.connect(app.quit)
        menu.addAction(quit)
        '''Give the menu to the tray'''
        self.setContextMenu(menu)
        
        '''Lets see where the menu is drawn'''
        menu.aboutToShow.connect(lambda: print(menu.pos()))
        
           
def main():
    '''Define app'''
    app = QApplication([])
    app.setQuitOnLastWindowClosed(False)
    
    '''System tray'''
    tray_icon = SystemTrayIcon(QIcon('icon.png'), app)

    app.exec()
    
if __name__ == '__main__':
    main()

The menu does not show up. The lambda print positions are interesting, on my screen the first code returns something like: PyQt6.QtCore.QPoint(1686, 1036) whereas the second code returns PyQt6.QtCore.QPoint(1686, 1064), which is about 30 pixels lower. My screen resolution is 1080p so it's not off the screen as such but does indicate some different behaviour here. Any ideas why the menu doesn't display in the second example?

Alex
  • 172
  • 9

1 Answers1

0

A reference to the QAction needs to be kept. This works:

from PyQt6.QtGui import QAction, QIcon
from PyQt6.QtWidgets import QSystemTrayIcon, QApplication, QMenu

class SystemTrayIcon(QSystemTrayIcon):
    
    def __init__(self, icon: QIcon, app: QApplication, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        '''setup'''
        self.setIcon(icon)
        self.show()
        
        '''Add a menu with a quit action'''
        menu = QMenu()
        self.quit = QAction("Quit")
        self.quit.triggered.connect(app.quit)
        menu.addAction(self.quit)
        '''Give the menu to the tray'''
        self.setContextMenu(menu)
        
        '''Lets see where the menu is drawn'''
        menu.aboutToShow.connect(lambda: print(menu.pos()))
        
           
def main():
    '''Define app'''
    app = QApplication([])
    app.setQuitOnLastWindowClosed(False)
    
    '''System tray'''
    tray_icon = SystemTrayIcon(QIcon('icon.png'), app)

    app.exec()
    
if __name__ == '__main__':
    main()
Alex
  • 172
  • 9
  • With menus and actions it's very important to decide and keep references and ownership depending on the situation. First of all, it's better to keep a reference to the menu, since the tray icon doesn't take ownership, so you should use `self.menu = QMenu()` (or just `menu = QMenu(someParent)` *if* the parent is a QWidget, which is not the case for QSystemTrayIcon). Also, unless the action is not used elsewhere, it's easier to use `menu.addAction('Quit')` or eventually `action = QAction('Quit', menu)`. – musicamante Sep 02 '22 at 14:51