Qt 5.12 QML,在javascript中通过var选择QML对象

Rom*_*lle 6 javascript c++ qt qml

我想知道是否有一种方法可以通过 var 选择具有特定idobjectName在 javascript 函数中已创建的 QML 对象(var 是与 QML 对象 ID 或名称相对应的字符串参数)。例如:

// main.qml

ApplicationWindow {

    RoundButton {
        id: btn1
    }

    RoundButton {
        id: btn2
    }

    RoundButton {
        id: btn3
    }

    // ...

    function foo(qmlObjectNameOrId) {
        qmlObjectNameOrId.text = "qmlObjectNameOrId is already in the document and has a property text that I want to set";

        // Qt.findQmlObject(id) would have been great !
    }
}
Run Code Online (Sandbox Code Playgroud)

Qt.createQmlObject不是一个解决方案,因为我想使用已经创建的 QML 对象。

在C++中,实现这一点的方法是使用QQmlApplicationEngine对象,然后使用QML根对象通过QML对象名称执行选择:

// main.qml

ApplicationWindow {

    RoundButton {
        id: btn1
    }

    RoundButton {
        id: btn2
    }

    RoundButton {
        id: btn3
    }

    // ...

    function foo(qmlObjectNameOrId) {
        qmlObjectNameOrId.text = "qmlObjectNameOrId is already in the document and has a property text that I want to set";

        // Qt.findQmlObject(id) would have been great !
    }
}
Run Code Online (Sandbox Code Playgroud)

javascript 函数将在 C++ 中调用QMetaObject::invokeMethod(appWindow, "foo", Q_ARG(QVariant, "bar"));

谢谢

[编辑1]尝试罗曼·斯维尔德洛夫的回答:

ApplicationWindow {
    id: appWindow
    objectName: "appWindow"
    // ...

    Pane {
        id: buttonsContainer
        objectName: "buttonsContainer"

        property string  disposition         : "circular_1"
        property int     btnWidth            : 130
        property int     btnHeight           : 130
        property int     btnIconWidth        : 40
        property int     btnIconHeight       : 40
        property int     btnRadius           : btnWidth / 2
        property int     btnMargin           : 40
        property int     btnZ                : 4
        property int     btnPressedBackground: Material.Purple

        anchors.right: parent.right
        anchors.left: parent.left
        anchors.top: instructionContainer.bottom
        anchors.bottom: parent.bottom
        visible: false

        Image {
            id: background
            height: buttonsContainer.height - 100
            x: (buttonsContainer.width - width) / 2
            y: (buttonsContainer.height - height) / 2
            source: "qrc:///images/circle_background.png"
            horizontalAlignment: Image.AlignHCenter
            verticalAlignment: Image.AlignVCenter
            fillMode: Image.PreserveAspectFit
        }

        Rectangle {
            id: topLeft
            color: Material.color(Material.Red)
            x: 0
            z: 1
            height: parent.height / 2
            width: parent.width / 2
        }

        Rectangle {
            id: topRight
            color: Material.color(Material.Green)
            x: parent.width / 2
            z: 1
            anchors.top: parent.top
            height: parent.height / 2
            width: parent.width / 2
        }

        Label {
            id: backgroundTextTop
            text: "MONTER"
            font.pixelSize: 40
            x: (parent.width - width) / 2
            y: (parent.height - height) / 2 - 50
            z: 2
        }

        Rectangle {
            id: bottomLeft
            color: Material.color(Material.Green)
            x: 0
            z: 1
            anchors.bottom: parent.bottom
            height: parent.height / 2
            width: parent.width / 2
        }

        Rectangle {
            id: bottomRight
            color: Material.color(Material.Red)
            x: parent.width / 2
            z: 1
            anchors.bottom: parent.bottom
            height: parent.height / 2
            width: parent.width / 2
        }

        Label {
            id: backgroundTextBottom
            text: "PLONGER"
            font.pixelSize: 40
            x: (parent.width - width) / 2
            y: (parent.height - height) / 2 + 200
            z: 2
        }

        RoundButton {
            id: btnB1MB
            objectName: "btnB1MB"
            width: buttonsContainer.btnWidth
            height: buttonsContainer.btnHeight
            radius: buttonsContainer.btnRadius
            z: buttonsContainer.btnZ
            display: AbstractButton.TextUnderIcon
            onPressed: {
                TestsRun.pressButton(Buttons.B1MB);
            }
            onReleased: {
                TestsRun.releaseButton(Buttons.B1MB);
            }
        }

        RoundButton {
            id: btnB4MT
            objectName: "btnB4MT"
            width: buttonsContainer.btnWidth
            height: buttonsContainer.btnHeight
            radius: buttonsContainer.btnRadius
            z: buttonsContainer.btnZ
            display: AbstractButton.TextUnderIcon
            onPressed: {
                TestsRun.pressButton(Buttons.B4MT);
            }
            onReleased: {
                TestsRun.releaseButton(Buttons.B4MT);
            }
        }

        RoundButton {
            id: btnB3MB
            objectName: "btnB3MB"
            width: buttonsContainer.btnWidth
            height: buttonsContainer.btnHeight
            radius: buttonsContainer.btnRadius
            z: buttonsContainer.btnZ
            display: AbstractButton.TextUnderIcon
            onPressed: {
                TestsRun.pressButton(Buttons.B3MB);
            }
            onReleased: {
                TestsRun.releaseButton(Buttons.B3MB);
            }
        }

        RoundButton {
            id: btnB4PB
            objectName: "btnB4PB"
            width: buttonsContainer.btnWidth
            height: buttonsContainer.btnHeight
            radius: buttonsContainer.btnRadius
            z: buttonsContainer.btnZ
            display: AbstractButton.TextUnderIcon
            onPressed: {
                TestsRun.pressButton(Buttons.B4PB);
            }
            onReleased: {
                TestsRun.releaseButton(Buttons.B4PB);
            }
        }

        RoundButton {
            id: btnB2MT
            objectName: "btnB2MT"
            width: buttonsContainer.btnWidth
            height: buttonsContainer.btnHeight
            radius: buttonsContainer.btnRadius
            z: buttonsContainer.btnZ
            display: AbstractButton.TextUnderIcon
            onPressed: {
                TestsRun.pressButton(Buttons.B2MT);
            }
            onReleased: {
                TestsRun.releaseButton(Buttons.B2MT);
            }
        }

        RoundButton {
            id: btnB1PT
            objectName: "btnB1PT"
            width: buttonsContainer.btnWidth
            height: buttonsContainer.btnHeight
            radius: buttonsContainer.btnRadius
            z: buttonsContainer.btnZ
            display: AbstractButton.TextUnderIcon
            onPressed: {
                TestsRun.pressButton(Buttons.B1PT);
            }
            onReleased: {
                TestsRun.releaseButton(Buttons.B1PT);
            }
        }

        RoundButton {
            id: btnB2PB
            objectName: "btnB2PB"
            width: buttonsContainer.btnWidth
            height: buttonsContainer.btnHeight
            radius: buttonsContainer.btnRadius
            z: buttonsContainer.btnZ
            display: AbstractButton.TextUnderIcon
            onPressed: {
                TestsRun.pressButton(Buttons.B2PB);
            }
            onReleased: {
                TestsRun.releaseButton(Buttons.B2PB);
            }
        }

        RoundButton {
            id: btnB3PT
            objectName: "btnB3PT"
            width: buttonsContainer.btnWidth
            height: buttonsContainer.btnHeight
            radius: buttonsContainer.btnRadius
            z: buttonsContainer.btnZ
            display: AbstractButton.TextUnderIcon
            onPressed: {
                TestsRun.pressButton(Buttons.B3PT);
            }
            onReleased: {
                TestsRun.releaseButton(Buttons.B3PT);
            }
        }

        Component.onCompleted: {
            setButtonsPosition(buttonsContainer.disposition);
        }
    }

    /**
     * Get a QML element by objectName property
     *
     * @todo Not working
     *
     * @param {String} objectName - The QML object name to get
     */
    function getQmlObjectByName(objectName) {
        console.log("buttonsContainer.children.length", buttonsContainer.children.length);
        return getQmlObjectByNameRecursive(buttonsContainer, objectName)
    }

    /**
     * Get a QML element by objectName property
     *
     * @todo Not working
     *
     * @param {Object} object - The QML object to find the QML element in
     * @param {String} objectName - The QML object name to get
     */
    function getQmlObjectByNameRecursive(object, objectName) {
        for (let child in object.children) {
            console.log(object.children[child].objectName);

            if (object.children[child].objectName === objectName) {
                console.log('found');
                return object.children[child];
            }

            if (typeof object.children[child].children !== 'undefined') {
                console.log('children', object.children[child]);
                return getQmlObjectByNameRecursive(object.children[child], objectName);
            }
        }
    }

Run Code Online (Sandbox Code Playgroud)

输出

qml: buttonsContainer.children.length 2
qml: Pane
qml: children QQuickContentItem(0x55c4e2a145d0, "Pane")
qml: 
qml: children QQuickImage(0x55c4e2a1cc80)
qml: undefined
Run Code Online (Sandbox Code Playgroud)

Rom*_*lle 1

通过迭代 QML 容器解决了问题,我想通过 objectName 属性在其中查找 QML 对象。

感谢Roman Sverdlov,“DOM 遍历”是通过contentChildren属性而不是children属性来完成的。

    /**
     * Get a QML element by objectName property in buttonsContainer container
     *
     * @param {String} objectName - The QML object name to get
     */
    function getQmlObjectByName(objectName) {
        for (let child in buttonsContainer.contentChildren) {
            if (buttonsContainer.contentChildren[child].objectName === objectName) {
                return buttonsContainer.contentChildren[child];
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)