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

时间:2019-02-20 10:17:41

标签: javascript c++ qt qml

我想知道是否有一种方法可以用var在javascript函数中选择具有特定idobjectName的已创建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 !
    }
}

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

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

int main(int argc, char *argv[])
{
    QQmlApplicationEngine engine;

    QString objectName = someFunction();

    QObject* qmlObject = engine.rootObjects()[0]->findChild<QObject*>(objectName);

    // use your qmlObject ...
}

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

谢谢

[编辑1]尝试Roman Sverdlov的答案:

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);
            }
        }
    }

输出

qml: buttonsContainer.children.length 2
qml: Pane
qml: children QQuickContentItem(0x55c4e2a145d0, "Pane")
qml: 
qml: children QQuickImage(0x55c4e2a1cc80)
qml: undefined

2 个答案:

答案 0 :(得分:1)

如果您为对象设置了objectName属性,则可以使用类似的

ApplicationWindow {
id: appWin
RoundButton {
    id: btn1
    objectName: "btn1"
}

RoundButton {
    id: btn2
    objectName: "btn2"
}

// ...

function foo(objectName) {
    for(var child in appWin.children) {
        if(appWin.children[child].objectName === objectName) {
            appWin.children[child].text = "qmlObjectNameOrId is already in the document and has a property text that I want to set";
            break
        }
    }
}

}

当然看起来很丑,但是如果您非常需要它...

答案 1 :(得分:1)

通过遍历一个我想通过objectName属性在其中找到QML对象的QML容器解决了问题。

由于罗马·斯维尔德洛夫,“ 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];
            }
        }
    }