3

I am trying to print a text when system tray icon is clicked in PyQT5 program. I tried to connect PyQT5 QSystemTrayIcon activated signal (emitted when system tray icon is clicked) to custom method, but the method is not called. Here is simple example:

import sys
from PyQt5.QtWidgets import QSystemTrayIcon, QApplication
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot


@pyqtSlot()
def action(signal):
    print('test1')

app = QApplication(sys.argv)
icon = QSystemTrayIcon(QIcon('any_icon.png'), app)
icon.show()

icon.activated.connect(action)
#icon.activated['QSystemTrayIcon::ActivationReason'].connect(action)
#icon.pyqtConfigure(activated=action)

print(icon.receivers(icon.activated))  # to check if is connected
sys.exit(app.exec_())

In example are 3 ways of connecting the signal to slot (two of them commented). I tried both using method with and without decorator @pyqtSlot(). Connection raises no errors. Even the print of signal receivers says it is connected to 1 slot. However, it does nothing when systray icon is clicked.

The question: Is the signal connection incorrect, or is the signal not emitted at all?

System: Ubuntu 16.04, PyQT5.8. However, should be working on others systems too as PyQT is multiplatform-ish. PS: I have read official PyQT5 signal/slot documentation and many related questions on stack overflow, but had not found the same issue. The closest one I think may relate is in C++, but not applicable to python. Any tips would be really appreciated. Thank you very much! Edit: fixed typos in text

Community
  • 1
  • 1
Filip Happy
  • 575
  • 5
  • 17
  • 1
    I have tried it and it works well. I'm using Arch Linux, PyQt5.8, Qt5.8 and gnome as desktop manager. – eyllanesc Apr 27 '17 at 22:35
  • @eyllanesc Thank you for trying it out and detailed info. I forgot to mention that I have _Ubuntu_ with _Unity_, not _Gnome_, so that led me to some testing and I think that there is a bug in _PyQT_ on _Unity_. More info in my answer below. – Filip Happy Apr 28 '17 at 15:33

2 Answers2

3

Your example works just fine in Xubuntu under openbox with stalonetray. However in Xubuntu proper it did not work ! But when I added something like:

mNu =  QMenu() 
test =  QAction('Test',mNu)
test.triggered.connect(action)
icon.setContextMenu(mNu)

it worked in xubuntu. I seems that somehow Ubuntu only expects to show a menu in the tray thing.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Murdo
  • 31
  • 1
  • The problem is I need to call the `action()` when systray icon is clicked, but the example above sends signal when the menu item is clicked. However, the fact it works on _Xubuntu_ helped me with testing and you gave me an idea how to bypass the problem using `QMenu()` - more in my currently added answer. Thank you very much! – Filip Happy Apr 28 '17 at 15:32
3

Based on @Murdo and @eyllanesc answers, I tested the sample code on multiple systems. Clean install only with Python 3.5 and pip3 install pyqt5. System tray icon activated signal is:

Not working:

  • Ubuntu 16.04 - Unity, PyQt 5.8 and PyQt 5.5.1
  • Ubuntu 16.10 - Unity, PyQt 5.8 and PyQt 5.7

Working:

  • Ubuntu 16.04 - Gnome, PyQt 5.8
  • Arch Linux - Gnome, PyQt 5.8
  • Kubuntu 16.10, KDE, PyQt 5.7
  • Xubuntu - Openbox with Stalonetray

It seems like the sample code is correct and there is a bug in QT using Unity - QSystemTrayIcon does not send activated signal when the system tray icon is clicked. Bug report link.

SOLUTION QSystemTrayIcon activation (clicked) signal can be bypassed by assigning a QMenu to the system tray icon and detecting QMenu().aboutToShow signal instead. This way when the tray icon is clicked, signal aboutToShow is sent, then menu displayed. It is not exactly the same result, but there seems to be no other way of detecting system tray icon activation on Unity. Thanks to @Murdo for an idea. Simple code example:

import sys
from PyQt5.QtWidgets import QApplication, QSystemTrayIcon, QMenu
from PyQt5.QtGui import QIcon


def action():
    print('System tray icon clicked.')

app = QApplication(sys.argv)
icon = QSystemTrayIcon(QIcon('any_icon.png'), parent=app)
icon.show()

menu = QMenu(parent=None)
menu.aboutToShow.connect(action)
icon.setContextMenu(menu)

sys.exit(app.exec_())
Filip Happy
  • 575
  • 5
  • 17
  • I'm having the same problem with PyQt 5.9 and Lubuntu 16.04 – sunyata Oct 11 '17 at 23:49
  • This is the only workaround I am aware of, but sadly it is unable to differ left/right clicks. Try to test different methods and the documentation - maybe you will find a solution. If you do, please share here with others. Good luck – Filip Happy Jun 08 '20 at 14:09