Search code examples
qtpropertiesqmlpyside

Update Text inside loaded qml file


We are having an ApplicationWindow based main.qml which is connected to our python backend via QmlElement Bridge. We have a view Slot-methods which directly return values to the qml frontend to change textfields which are children of the ApplicationWindow like the following:

ApplicationWindow {
    id: mainFrame
    width: 1280
    height: 720
    visible: true
    title: qsTr("Test")

    StackView {
        id: stack
        initialItem: loginFrame
        anchors.fill: parent
    }

    Bridge {
        id: bridge
    }

    Component{
        id: loginFrame

        ColumnLayout {
            anchors.margins: 3
            spacing: 3
            Layout.columnSpan: 1
            Layout.alignment: Qt.AlignHCenter

            Text {
                id: title
                Layout.alignment: Qt.AlignHCenter
                font.pointSize: 16
                text: "Login Screen"
                Layout.preferredHeight: 100

            }
            Button {
                id: loginButton
                Layout.alignment: Qt.AlignHCenter
                text: "login"
                highlighted: true
                Material.accent: Material.Red
                onClicked: {
                    title.text = bridge.login(username.text, password.text)
                }
            }
        }
    }
}

To reduce the size of our main.qml we decided to load the other Layouts, Components etc from different files with

Loader {
    id: otherLoader
    source: "other.qml"
}

How to access the Text Object inside of other.qml to update the text property from main.qml because the value is provided by the Bridge?

I already tried Accessing TextField from Another QML File but this hasn't worked.


Solution

  • The Loader creates items in not the same context as the statically create item use so cannot access the loaded item. You have several ways to access such an item.

    The first and the most correct way is to use a declarative style:

    Item {
        id: container
        anchors.fill: parent
        property string someText: "press again"
        Loader {
            id: loader
            active: false
            sourceComponent: Text {
                id: txt
                text: container.someText
            }
        }
        MouseArea {
            anchors.fill: parent
            onClicked: {
                if(loader.active)
                    container.someText = "some text"
                else
                    loader.active = true
            }
        }
    }
    

    You can create a binding in a Javascript code whenever you want:

        Loader {
            id: loader
            active: false
            sourceComponent: Text {
                id: txt
                Component.onCompleted: {
                    txt.text = Qt.binding(function() { return container.someText; })
                }
            }
        }
    

    Another option is using Loader.item property:

    Item {
        id: container
        anchors.fill: parent
        property string someText: "some text"
        Loader {
            id: loader
            active: false
            sourceComponent: Text {
                id: txt
                text: "press again"
            }
        }
    
        MouseArea {
            anchors.fill: parent
            onClicked: {
                if(loader.active)
                    loader.item.text = "some text"
                else
                    loader.active = true
            }
        }
    }