Search code examples
pythonpyqt5qsystemtrayicon

PyQT5 qsytemtrayicon


I have problem with qsystemtray. When I run code this code without "while", I can watch the icon. With while I can't watch icon (I checked that the program enters the condition "if (a.inbox.unread_count)> 0"), but region where icon must be not available.That is, the tray icon appears, but is not drawn. Are there any methods to solve this problem? OS: Astra-linux(fork debian)

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'qttray.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets
import extest4
import time
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1014, 680)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setMaximumSize(QtCore.QSize(800, 547))
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.centralwidget)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.horizontalLayout_2.addLayout(self.horizontalLayout)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1014, 30))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    email = 'testemail'
    server = '********'
    tr = QtWidgets.QSystemTrayIcon(QtGui.QIcon(r'payments.PNG'), app)
    print(tr.isSystemTrayAvailable())
    while(1):
        a = extest4.connect(server, email)
        if(a.inbox.unread_count)>0:
            a.inbox.refresh()
            tr.setVisible(True)
            tr.show()
        else:
            tr.hide()
        extest4.close_connections()
        time.sleep(10)
    sys.exit(app.exec_())

Solution

  • You have 3 blocking conditions: the while cycle, the mail checking and the time.sleep. All of them will lock the interface (that allows painting and interaction within the application main event loop) in some way, with the while being the "most locking" one: until it exits, the GUI is blocked, so the icon is not painted (as a matter of fact, nothing related to the GUI would work, including the main window if you had shown it).

    Since the mail checking might require some time to be processed, you will need to put that in a separate thread.

    In this example I have put the logic inside a subclass of the mainwindow, because you'll probably use that as the main "container" for your program. Other alternatives include using subclasses of QObject or the QApplication itself.

    server = 'mail.mailserver.com'
    email = '[email protected]'
    
    class MailChecker(QtCore.QThread):
        mailAvailable = QtCore.pyqtSignal(bool)
        def __init__(self, server, mail):
            super().__init__()
            self.server = server
            self.mail = mail
    
        def run(self):
            while True:
                a = extest4.connect(self.server, self.email)
                if a.inbox.unread_count > 0:
                    a.inbox.refresh()
                    self.mailAvailable.emit(True)
                else:
                    self.mailAvailable.emit(False)
                extest4.close_connections()
                QtCore.QThread.sleep(10)
    
    
    class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
        def __init__(self):
            super().__init__()
            self.setupUi(self)
            self.trayIcon = QtWidgets.QSystemTrayIcon(
                QtGui.QIcon(r'payments.PNG'), self)
            self.trayIcon.activated.connect(self.show)
            self.mailChecker = MailChecker(server, email)
            self.mailChecker.mailAvailable.connect(self.trayIcon.setVisible)
            self.mailChecker.start()
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)
        mainWindow = MainWindow()
        sys.exit(app.exec_())