Search code examples
pythonqmlpyside2

Get root object from pyside2


i have small application that i want to minimize to system tray, and i do have code that creates icon and minimizes it to system tray on push of a button, (on purpose i did not want to overwrite default close operation).

How ever, i dont know how to get my root object from qml, so i am unable to perform any action, and when i would get it, what type would it be ?

app = QApplication(sys.argv)

engine = QQmlApplicationEngine()
manager = Manager()
ctx = engine.rootContext()
ctx.setContextProperty("Manager", manager)
engine.load('main.qml')
if not engine.rootObjects():
    sys.exit(-1)
app.setWindowIcon(QtGui.QIcon('ico.png')) 
sys.exit(app.exec_()) 



class Manager(QObject):
 def __init__(self):
    QObject.__init__(self)


 self.tray_icon = QSystemTrayIcon(self)

now the following code i made to "work" on my application, even though is not working properly.

self.tray_icon.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
    show_action = QAction("Show", self)
    quit_action = QAction("Exit", self)
    hide_action = QAction("Hide", self)
    show_action.triggered.connect(self.show)
    hide_action.triggered.connect(self.hide)
    quit_action.triggered.connect(qApp.quit)
    tray_menu = QMenu()
    tray_menu.addAction(show_action)
    tray_menu.addAction(hide_action)
    tray_menu.addAction(quit_action)
    self.tray_icon.setContextMenu(tray_menu)
    self.tray_icon.show()


def minimize(self):
    self.hide()
    print("Test")
    _translate = QtCore.QCoreApplication.translate
    #self.hide()
    self.tray_icon.showMessage(
            "Tray Program",
            "Application was minimized to Tray",
            QSystemTrayIcon.Information,
            2000
        ) 

the only thing i did i changed

class Manager(QObject): to (QMainWindow)

and i could use this code, but instead manipulating my window, i got the completly new window, nonetheless i did get normal system tray icon and all menu items i needed.

So bottom line, how can i get reference of my root, and how can i use minimize to tray on it.

root of my QML is normal ApplicationWindow.

Just a small edit, i saw on some c++ examples they used to use ,

root = engine.rootObjects().at(0);

but this does not work anymore as i have seen. but i havent found any similar way.


Solution

  • In C++ rootObjects() returns a QList and the method at(i) returns the i-th object, in the case of at(0) returns the first element, in the case of Python rootObjects() returns a list, and to access the first element in python you should only use rootObjects()[0].

    If you are still using the code of your previous questions it is not advisable to mix classes, in the case of Manager had another objective so it is advisable to create another class specialized in handling the QSystemTrayIcon.

    If you are using QQmlApplicationEngine then you must be using ApplicationWindow or Window, and these classes inherit from QQuickWindow so we can use their methods since in Python the casting is automatic unlike C++, QQuickWindow has the method close, show and hide.

    import sys
    import os
    
    from PySide2.QtCore import Qt, QObject, Signal, Slot, Property
    from PySide2.QtWidgets import QApplication, QSystemTrayIcon, QStyle, QAction, QMenu, QMessageBox
    from PySide2.QtQml import QQmlApplicationEngine
    
    my_list = ['here','is','my','list']
    
    class Manager(QObject):
        ...
    
    class SystemTrayIconManager(QObject):
        def __init__(self, window, parent=None):
            QObject.__init__(self, parent)
            self.window = window
            self.window.closing.connect(self.onClosing)
            self.tray_icon = QSystemTrayIcon(self)
            self.tray_icon.setIcon(qApp.style().standardIcon(QStyle.SP_MediaPlay))
            show_action = QAction("Show", self)
            quit_action = QAction("Exit", self)
            hide_action = QAction("Hide", self)
            minimize_action = QAction("Minimize", self)
            show_action.triggered.connect(self.window.show)
            hide_action.triggered.connect(self.window.hide)
            quit_action.triggered.connect(qApp.quit)
            minimize_action.triggered.connect(self.minimize)
            tray_menu = QMenu()
            tray_menu.addAction(show_action)
            tray_menu.addAction(hide_action)
            tray_menu.addAction(quit_action)
            tray_menu.addAction(minimize_action)
            self.tray_icon.setContextMenu(tray_menu)
            self.tray_icon.show()
    
        def onClosing(self):
            if self.tray_icon.isVisible():
                QMessageBox.information(None, "Systray",
                        "The program will keep running in the system tray. To "
                        "terminate the program, choose <b>Quit</b> in the "
                        "context menu of the system tray entry.")
                self.window.hide()
    
        def minimize(self):
            self.window.hide()
            self.tray_icon.showMessage(
                    "Tray Program",
                    "Application was minimized to Tray",
                    QSystemTrayIcon.Information,
                    2000
                ) 
    
    
    if __name__ == "__main__":
        os.environ["QT_QUICK_CONTROLS_STYLE"] = "Material"
        app = QApplication(sys.argv)
    
        if not QSystemTrayIcon.isSystemTrayAvailable():
            QMessageBox.critical(None, "Systray",
                    "I couldn't detect any system tray on this system.")
            sys.exit(1)
    
        QApplication.setQuitOnLastWindowClosed(False)
        engine = QQmlApplicationEngine()
        manager = Manager()
        ctx = engine.rootContext()
        ctx.setContextProperty("Manager", manager)
        engine.load('main.qml')
    
        if not engine.rootObjects():
            sys.exit(-1)
        m = SystemTrayIconManager(engine.rootObjects()[0])
        manager.list_fill()
        sys.exit(app.exec_()) 
    

    You can find the complete code in the following link