6

I wonder if there is a way to select an already created QML object with a specific id or objectName in a javascript function by var (the var is a string parameter corresponding to the QML object id or name). Eg:

// 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 !
    }
}

The Qt.createQmlObject is not a solution as I want to use already created QML objects.

In C++, the way to achieve this is to use QQmlApplicationEngine object and then use the QML root object to perform the selection by QML object name :

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

    QString objectName = someFunction();

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

    // use your qmlObject ...
}

The javascript function would be called in C++ with QMetaObject::invokeMethod(appWindow, "foo", Q_ARG(QVariant, "bar"));

Thanks

[EDIT 1] Attempt to Roman Sverdlov answer:

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

output

qml: buttonsContainer.children.length 2
qml: Pane
qml: children QQuickContentItem(0x55c4e2a145d0, "Pane")
qml: 
qml: children QQuickImage(0x55c4e2a1cc80)
qml: undefined
3
  • Hi, I cannot use the direct QML id in js because the id is built with a parameter given by the js function called in C++. Commented Feb 21, 2019 at 13:12
  • Hi again, my apologies for misunderstanding your question. I've cleaned up your question a bit. (Thanks also for adding more context.) Additionally, I've found these relevant posts: Find a QML Object by ID. Find a QML Object by Object Name. Commented Feb 21, 2019 at 13:34
  • Thanks, I don't think there is a solution to this problem and it is considered an "anti pattern" in Qt. I just wanted to make my QML more compact and minimalist with some meta programming but it doesn't seem to be allowed with Qt Commented Feb 21, 2019 at 15:43

2 Answers 2

1

if you have objectName property set for your objects then you can use something like

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

}

Of course it looks ugly, but if you need it a lot...

Sign up to request clarification or add additional context in comments.

4 Comments

Not so ugly, I didn't know I could traverse the QML like a DOM in HTML with javascript. I'm going to test this and update the question if it works.
the appWin has no property children, console.log(appWin.children) === undefined
Then I think only Item can have children. So try to put your buttons inside some item , e.g. ColumnLayout and repeat
Seems like the container does not have all the children in its children property... I'll post the attempt to you solution with the code in the question
1

Problem solved by iterating over a QML container which I want to find the QML object by objectName property in.

Thanks to Roman Sverdlov, the "DOM traversal" is done with the contentChildren property and not children property.

    /**
     * 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];
            }
        }
    }

1 Comment

wow, this is such a bad design for the framework...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.