pythonpyqtqmlpyqt5applicationwindow

How can I send parent to a new ApplicationWindow


I want to recover the position and the size of the master "main.qml". But I do not know how to declare the parent of the new window. I have no problem if I open the window directly from the window main.qml in javascript but through python I do not see how.

I think I have to use "self.win" but how declare it ?

Thanks for yours responses.

test.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
import sys

class Main2(QObject):

    def __init__(self, engine, what_send_for_send_the_parent):
        QObject.__init__(self)

        """ 
        How can I say to the new windows who is the parent  ?
        """
        context = engine.rootContext()
        context.setContextProperty("py_Page2", self)
        engine.load('test2.qml')
        self.win = engine.rootObjects()[0]  

class Main(QObject):

    def __init__(self, engine):
        QObject.__init__(self)

        self.context = engine.rootContext()
        self.property = self.context.setContextProperty("py_Page", self)
        self.load = engine.load('test.qml')
        self.win = engine.rootObjects()[0]  

        print("Context", self.context)  # <PyQt5.QtQml.QQmlContext object at 0xb65e6f30>
        print("Property", self.property)# None
        print("Load", self.property)    # None
        print("Win", self.win)          # <PyQt5.QtGui.QWindow object at 0xb65e6f80>

if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    main = Main(engine) 
    main2 = Main2(engine, "???")

    engine.quit.connect(app.quit)
    sys.exit(app.exec_())

test.qml

import QtQuick 2.5
import QtQuick.Controls 1.4

ApplicationWindow {
    id: "main"
    visible: true
    width: 200; height: 240;    
    Text {text: qsTr("main")} 
}

test2.qml

import QtQuick 2.5
import QtQuick.Controls 1.4

ApplicationWindow {
    id: "main2"
    visible: true
    width: 200; height: 240;
    x: main.x
    y: main.y
    Text {text: qsTr("main2")}
}

I think I have found :

class Main2(QObject):

    def __init__(self, engine, master):
        QObject.__init__(self)
        context = engine.rootContext()
        context.setContextProperty("main_x", master.win.property("x"))
        context.setContextProperty("main_y", master.win.property("y"))
        engine.load('test2.qml')

...
    main = Main(engine) 
    main2 = Main2(engine, main)
...

And in the file qml

ApplicationWindow {
    id: "main2"
    visible: true
    width: 200; height: 240;
    x: main_x + 20
    y: main_y + 120
    Text {text: qsTr("main2")}
}

I can recover the value like that. Is this correct? Is there a more conventional way?


Solution

  • Although the solution works in this case it can fail in more real cases where each QML can load many components since the QML load is asynchronous but your procedure is synchronous.

    The solution is to create a QObject and export it to QML using setContextProperty() so that it is accessible from all the QMLs that are loaded through the QQmlApplicationEngine. That QObject must have a property that is a mirror of the property you want to obtain.

    main.py

    from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, QPoint, QUrl
    from PyQt5.QtGui import QGuiApplication
    from PyQt5.QtQml import QQmlApplicationEngine
    
    
    class Manager(QObject):
        positionChanged = pyqtSignal()
    
        def __init__(self, parent=None):
            super().__init__(parent)
            self._position = QPoint()
    
        @pyqtProperty(QPoint, notify=positionChanged)
        def position(self):
            return self._position
    
        @position.setter
        def position(self, p):
            if self._position != p:
                self._position = p
                self.positionChanged.emit()
    
    
    if __name__ == "__main__":
        import os
        import sys
    
        app = QGuiApplication(sys.argv)
    
        engine = QQmlApplicationEngine()
        manager = Manager()
        engine.rootContext().setContextProperty("manager", manager)
    
        current_dir = os.path.dirname(os.path.realpath(__file__))
    
        engine.load(QUrl.fromLocalFile(os.path.join("test.qml")))
        engine.load(QUrl.fromLocalFile(os.path.join("test2.qml")))
    
        engine.quit.connect(app.quit)
        sys.exit(app.exec_())
    

    test.qml

    import QtQuick 2.5
    import QtQuick.Controls 1.4
    
    ApplicationWindow {
        id: root
        visible: true
        width: 200
        height: 240
        Text {
            text: qsTr("main")
        }
        Component.onCompleted: manager.position = Qt.point(root.x, root.y)
    }
    

    test2.qml

    import QtQuick 2.5
    import QtQuick.Controls 1.4
    
    ApplicationWindow {
        visible: true
        width: 200
        height: 240
        x: manager.position.x
        y: manager.position.x
        Text {
            text: qsTr("main2")
        }
    }