0
votes

I had a problem with the item in QML. I wanna get children of an item but it seems working in the first element.

The detail code is below:

I have a gridview with a list custom component AAA_Styles

GridView{
    id: grdViewDeviceControl
    clip: true
    interactive: true
    ScrollIndicator.vertical: ScrollIndicator{}
    cellWidth: 200
    cellHeight: 300

    model: ListModel{}

    delegate: Item {
        width: grdViewDeviceControl.cellWidth
        height: grdViewDeviceControl.cellHeight
        AAA_Styles{
            id: deviceControl
            objectName: "deviceControl"
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.verticalCenter: parent.verticalCenter
            name: Names
            subname: Subnames
    }
}

My custom AAA_RTS is a QML component have some functions such as:
- function_a()
- function_b()
I added 2 items into model using

grdViewDeviceControl.model.append()

I ensure the model have data that I added because It appeared in my design and the count of gridview is 2 elements

console.log(grdViewDeviceControl.count) //the result is 2

After that, I tried to get each element to access functions that they are available using a method in signal onRelease of a button:

onReleased: {
    console.log("number of item: " + grdViewDeviceControl.count)
    var myRTS = grdViewDeviceControl.contentItem.children[0]
    console.log(myRTS)
    console.log(myRTS.children[0])
    myRTS = grdViewDeviceControl.contentItem.children[1]
    console.log(myRTS)
    console.log(myRTS.children[1])
}

The result on console:

qml: number of item: 2
qml: QQuickItem(0x9828f60)
qml: AAA_Styles_QMLTYPE_0_QML_112(0x9829070, "deviceControl")
qml: QQuickItem(0x5554140)
qml: undefined

With the first element grdViewDeviceControl.contentItem.children[0], I access function_a or function_b successful but when I using the second the error appeared

TypeError: Cannot call method 'function_a' of undefined

So can anyone tell me why I wrong and how to fix it?

Many thanks for any help!

1
It is a bad practice to access the items in a view since it brings problems such as what you point out, instead you should interact with the model information. Why do you want to access the items? - eyllanesc
Yes, I don't know the best way to do that. Thank you for the recommendation and how to access the model? I guess I have to create a model outside of gridview and access it by id - Chinh Nguyen Huu
Exactly, check an old answer from me stackoverflow.com/a/55318200/6622587 - eyllanesc
The possible solution that you indicate can work but I am not analyzing it because for me it is not the correct solution since it is difficult to maintain, for example if you change the component you will have to modify another part of the code. That is, your possible solution is a temporary patch that in the future will give you many headaches (I already had them when I started with QML and I do not want to have them again). For me you have a XY problem, that is, you are asking for an answer that no one guarantees works, instead of your underlying problem. - eyllanesc
I think the comments have already been extended. The last thing I'll say is that you first design your components before implementing them. Many times we have the bad habit of writing code without having a clear vision of what is desired (the design), read What is the XY problem? bye - eyllanesc

1 Answers

1
votes

Do not try to access directly to the child items. Use delegate IDs, signals and slots instead:

  • Give a "delegate ID" to all your delegates through the model of your GridView.
  • In your GridView, add signals that will be used to broadcast to all the delegates the following things:
    • The "delegate ID" of the delegate that you want it to execute the function.
    • The arguments for the AAA_Styles function.
  • In your delegate, add one slot per AAA_Styles function. Each slot will execute the AAA_Styles function only if the broadcasted delegate ID is the delegate's: if (broadcastedID === delegateID) { function_ab() }.
  • When you want to execute function_a() or function_b() in a delegate, broadcast the delegate ID and the function arguments through the corresponding GridView signal (in onReleased, for example).

The following piece of code sums up what I have just described to you. If it does not work put the delegate in a separated QML file. This should work for good:

// Your grid
GridView {
    id: grdViewDeviceControl
    clip: true
    interactive: true
    ScrollIndicator.vertical: ScrollIndicator {}
    cellWidth: 200
    cellHeight: 300

    model: ListModel {
        /*
            Example of list element:
            ListElement { m_uuid: "{element-uuid}" }
        */
    }

    delegate: Item {
        width: grdViewDeviceControl.cellWidth
        height: grdViewDeviceControl.cellHeight

        AAA_Styles {
            id: deviceControl
            objectName: "deviceControl"
            anchors.centerIn: parent
            name: Names
            subname: Subnames
        }

        // The delegate ID
        property string delegate_id: m_uuid

        // Broadcast receivers
        function delfunc_a(uuid, argA0) {
            if (uuid === this.delegate_id) {
                deviceControl.function_a(argA0)
            }
        }

        function delfunc_b(uuid, argB0, argB1) {
            if (uuid === this.delegate_id) {
                deviceControl.function_b(argB0, argB1)
            }
        }

        // Connecting broadcasters to receivers
        Component.onCompleted: {
            grdViewDeviceControl.exec_a.connect(this.delfunc_a)
            grdViewDeviceControl.exec_b.connect(this.delfunc_b)
        }

        Component.onDestruction: {
            grdViewDeviceControl.exec_a.disconnect(this.delfunc_a)
            grdViewDeviceControl.exec_b.disconnect(this.delfunc_b)
        }
    }

    // Your broadcasters
    signal exec_a(string uuid, int argA0)
    signal exec_b(string uuid, bool argB0, string argB1)
}
// Somewhere else in your code:
onReleased: {
    /*
     * Only the delegate whose ID is "{a-given-uuid}"
     * will execute deviceControl.function_a(3):
     */
    grdViewDeviceControl.exec_a("{a-given-uuid}", 3)
    /*
     * Only the delegate whose ID is "{another-given-uuid}"
     * will execute deviceControl.function_b(true, "U got style!"):
     */
    grdViewDeviceControl.exec_b("{another-given-uuid}", true, "U got style!")
}