Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Setting context property for individual QML UI element



  • Hello,
    I am in process of learning Qt and writing it in python. So far progress is good, but I've come across one problem which I don't know how to solve. Let's look at a sample app:

    # foo.py
    from PySide2.QtCore import QObject, Property, Slot
    
    class FooController(QObject):
        def __init__(self, parent=None):
            QObject.__init__(self, parent)
            self.__text = "Foo"
    
        @Property(str)
        def text(self):
            return self.__text
    
        @Slot()
        def clickListener(self):
            print('Foo')
    
    // Foo.qml
    import QtQuick 2.9
    import QtQuick.Controls 2.2
    
    Button {
        text: fooController.text
        onClicked: fooController.clickListener()
    }
    
    # bar.py
    from PySide2.QtCore import QObject, Property, Slot
    
    class BarController(QObject):
        def __init__(self, parent=None):
            QObject.__init__(self, parent)
            self.__text = "Bar"
    
        @Property(str)
        def text(self):
            return self.__text
    
        @Slot()
        def clickListener(self):
            print('Bar')
    
    // Bar.qml
    import QtQuick 2.9
    import QtQuick.Controls 2.2
    
    Button {
        text: barController.text
        onClicked: barController.clickListener()
    }
    
    # main.py
    import sys
    from PySide2.QtCore import QUrl
    from PySide2.QtGui import QGuiApplication
    from PySide2.QtQml import QQmlApplicationEngine
    
    from lib.bar.bar import BarController
    from lib.foo.foo import FooController
    
    if __name__ == '__main__':
        app = QGuiApplication(sys.argv)
        engine = QQmlApplicationEngine()
    
        fooController = FooController()
        barController = BarController()
    
        engine.rootContext().setContextProperty("fooController", fooController)
        engine.rootContext().setContextProperty("barController", barController)
        engine.load(QUrl.fromLocalFile('main.qml'))
    
        if not engine.rootObjects():
            sys.exit(-1)
        sys.exit(app.exec_())
    
    // main.qml
    import QtQuick.Controls 2.2
    import QtQuick 2.10
    import "./foo"
    import "./bar"
    
    ApplicationWindow {
        visible: true
    
        Row {
            Foo {}
            Bar {}
        }
    }
    

    This sample app works as intended: two buttons are displayed with names 'Foo' and 'Bar', and on click they print text in console.
    What I don't like, is that currently I am setting context properties for both components in main:

    engine.rootContext().setContextProperty("fooController", fooController)
    engine.rootContext().setContextProperty("barController", barController)
    

    This results in controllers being available globally in qml. What I want to achieve is modular approach. I can imagine that it would look like this - in main.py:

    context = engine.rootContext()
    fooController.attachToContext(context)
    barController.attachToContext(context)
    

    and corresponding methods in controllers:

     def attachToContext(self, context):
            elemContext = context.findQmlElementByName("Foo").context()
            elemContext.setContextProperty("controller", self)
    

    This way (I guess) controllers could be isolated and only accessed by the view they are set to, also this way name conflicts could be avoided. But this is theory, as I have no idea how could I achieve this - I've looked for solutions, but to no avail.

    Thank you in advance for any suggestions


  • Qt Champions 2017

    What you are looking for is two separate context and expose the object separately. If this is the case did you get a chance to look at QQmlContext documentation. It has an example expose with different contexts.



  • @dheerendra said in Setting context property for individual QML UI element:

    What you are looking for is two separate context and expose the object separately. If this is the case did you get a chance to look at QQmlContext documentation. It has an example expose with different contexts.

    I would like to know this as well.

    The documentation only describes how to create a QQmlContext as a child of another QQmlContext, but doesn't say anything about how to retrieve or set a QQmlContext for a particular QQuickWidget.


Log in to reply