Search code examples
pythonpyqtpyqt5qsystemtrayicon

Implement Popup mapping in QSystemTrayIcon


I want to implement behaviour of a popup-window exactly like default volume controller in windows 10. One click on icon, window opens or closes; if window is opened, clicking outside it will close the window. How can i implement this?

Before, i found that it is possible for the widget to override the methods for pressing and releasing the mouse keys, but here it was not found, or it was poorly searched. Help me please.

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QGridLayout, \
                            QWidget, QSystemTrayIcon, QStyle, qApp
import PyQt5.QtCore


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setMinimumSize(PyQt5.QtCore.QSize(600, 130))
        self.setMaximumSize(PyQt5.QtCore.QSize(600, 130))

        self.setWindowFlags(PyQt5.QtCore.Qt.Popup)

        screen_geometry = QApplication.desktop().availableGeometry()
        screen_size = (screen_geometry.width(), screen_geometry.height())
        win_size = (self.frameSize().width(), self.frameSize().height())
        x = screen_size[0] - win_size[0]
        y = screen_size[1] - win_size[1]
        self.move(x, y)
        self.setWindowOpacity(0.85)
        self.setWindowTitle("System Tray Application")
        central_widget = QWidget(self)
        self.setCentralWidget(central_widget)

        grid_layout = QGridLayout(central_widget)
        grid_layout.addWidget(QLabel("Application, which can minimize to tray",
                                     self), 0, 0)

        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(self.
                               style().standardIcon(QStyle.SP_ComputerIcon))
        self.tray_icon.activated.connect(self.trigger)
        self.tray_icon.show()

        self.setGeometry(500, 570, 600, 130)
        self.fl = False

    def trigger(self, reason):
        if reason == QSystemTrayIcon.MiddleClick:
            qApp.quit()
        elif reason == QSystemTrayIcon.Trigger:
            if not self.fl:
                self.show()
            else:
                self.hide()
            self.fl = not self.fl
        elif reason == 1:
            self.fl = False

    # def mouseReleaseEvent(self, event):
    #     self.hide()
    #     self.fl = False


if __name__ == "__main__":
    app = QApplication(sys.argv)
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec())


Solution

  • If you want to toggle visibility then you must use the setVisible() and isVisible() methods:

    import sys
    
    from PyQt5.QtWidgets import (
        QApplication,
        QGridLayout,
        QLabel,
        QMainWindow,
        QStyle,
        QSystemTrayIcon,
        QWidget,
    )
    from PyQt5.QtCore import Qt, QSize
    
    
    class MainWindow(QMainWindow):
        def __init__(self):
            super().__init__()
    
            self.setFixedSize(600, 130)
    
            self.setWindowFlag(Qt.Popup)
    
            self.setWindowOpacity(0.85)
            self.setWindowTitle("System Tray Application")
            central_widget = QWidget()
            self.setCentralWidget(central_widget)
    
            grid_layout = QGridLayout(central_widget)
            grid_layout.addWidget(QLabel("Application, which can minimize to tray"), 0, 0)
    
            self.tray_icon = QSystemTrayIcon(self)
            self.tray_icon.setIcon(self.style().standardIcon(QStyle.SP_ComputerIcon))
            self.tray_icon.activated.connect(self.trigger)
            self.tray_icon.show()
    
            self.setGeometry(
                QStyle.alignedRect(
                    Qt.LeftToRight,
                    Qt.AlignBottom | Qt.AlignRight,
                    self.window().size(),
                    QApplication.desktop().availableGeometry(),
                )
            )
    
        def trigger(self, reason):
            if reason == QSystemTrayIcon.MiddleClick:
                QApplication.quit()
            elif reason == QSystemTrayIcon.Trigger:
                self.setVisible(not self.isVisible())
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        mw = MainWindow()
        mw.show()
        sys.exit(app.exec())