Search code examples
pythonpyside2system-tray

Trouble with executing "While" loop, using system tray on Python


I'm trying to create application which runs block of code every X seconds, which has system tray icon with only "Quit" option. But the problem is that when it get to the tray function, it doesn't read next lines of code, and as a result, "While" loop can't be launched. Is there any other approach to do that?

import time
import os
import sys
from PySide2 import QtWidgets, QtGui

class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
    def __init__(self, icon, parent=None):
        QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
        self.setToolTip(f'Wallpy')
        menu = QtWidgets.QMenu(parent)

        exit_ = menu.addAction("Exit")
        exit_.triggered.connect(lambda: sys.exit())

        menu.addSeparator()
        self.setContextMenu(menu)


def tray():
    app = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QWidget()
    tray_icon = SystemTrayIcon(QtGui.QIcon("tray.ico"), w)
    tray_icon.show()
    app.exec_()


def loop_function():
    print("Nice") # anything executable


tray() # launch tray icon


while True:
    loop_function() # executing every minute
    time.sleep(60)

Solution

  • Its because, when you used the tray(), your main application started and the GUI main loop is initiated. It runs till your application exits, after which the while loop is executed.

    However, if you want the loop to run simultaneously, you should integrate it with Qt's main loop. In Gtk we do this using GLib.add_main_thread and other methods, I don't know about Qt, but you can use this general solution using Threading.

    from threading import Thread
    import time
    import os
    import sys
    from PySide2 import QtWidgets, QtGui
    
    
    def loop_function():
        print("Nice") # anything executable
    
    def thread_loop():
        while True:
            loop_function() # executing every minute
            time.sleep(60)
    
    class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
        def __init__(self, icon, parent=None):
            QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
            self.setToolTip(f'Wallpy')
            menu = QtWidgets.QMenu(parent)
    
            exit_ = menu.addAction("Exit")
            exit_.triggered.connect(lambda: sys.exit())
    
            menu.addSeparator()
            self.setContextMenu(menu)
    
    
    def tray():
        app = QtWidgets.QApplication(sys.argv)
        w = QtWidgets.QWidget()
        tray_icon = SystemTrayIcon(QtGui.QIcon("tray.ico"), w)
        tray_icon.show()
        app.exec_()
    
    my_loop = Thread(target=thread_loop, args=()) # Start the thread with no args
    my_loop.start()
    tray() # launch tray icon