Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

List of lists refreshing error



  • Hello friends!
    I've got some problem in QML. I made a list of lists with ListView. The main list's model is ObjectModel. SubList's model is ListModel with horizontalView. Both of them are populated dynamically. The problem is that, when I clear my ObjectModel and reappend those objects(refresh the list) again, it clears, but crashes with somehow problem. Here is my code:
    //--------Main list's ObjectModel--------
    ObjectModel{

        id: groups
        Component{
            id: groupItem
    
            Item {
                height: 280
                width: lvGroups.width
                clip: true
                property string groupName: "New" // Caption of the group
    
                Text {
                    id: groupCaption
                    anchors {
                        topMargin: 8
                        leftMargin: 32
                    }
                    font.pointSize: txtSize+6
                    text: '<b>'+groupName+'</b>'
                }
    
                ListModel {
                    id: itemList
            //        ListElement {  //subList's Item structure
            //            name: "product"
            //            cost: "12500.00"
            //            icon: "file://"
            //            group: "grp_0"
            //        }
                }
    
                function addItem(nm, cs, grp, icn) // function to add item for subList's model
                { itemList.append({'name': nm, 'cost': cs, 'group': grp, 'icon': icn}) }
                //function clearItems() { itemList.clear() }
    
                ListView{ // subList with horizontalView
                    width: parent.width
                    anchors {
                        bottom: groupItem.bottom
                        top: groupCaption.bottom
                    }
                    orientation: ListView.Horizontal
                    spacing: 8
                    boundsBehavior: Flickable.StopAtBounds
                    model: itemList
                    delegate: Item{
                        width: 180
                        height: parent.height-16
                        anchors.verticalCenter: parent.verticalCenter
                        Image {
                            id: itemIcon
                            anchors.horizontalCenter: parent.horizontalCenter
                            width: 120
                            height: 120
                            source: icon!='' ? icon : "res/image.png"
                        }
                        Text{
                            id: nametxt
                            text: name
                            anchors{
                                top: itemIcon.bottom
                                topMargin: 8
                                horizontalCenter: parent.horizontalCenter
                            }
                            font.pointSize: txtSize
                            elide: Text.ElideRight
                            Component.onCompleted:
                            if (width>parent.width-16) width=parent.width-16
                        }
                        Text{
                            text: cost
                            anchors{
                                top: nametxt.bottom
                                topMargin: 4
                                horizontalCenter: parent.horizontalCenter
                            }
                            font.pointSize: txtSize
                            Component.onCompleted:
                            if (width>parent.width-16) width=parent.width-16
                        }
                        MouseArea{
                            anchors.fill: parent
                            onClicked: { addToBacket(name, cost) } //it's a function outside that adds to another list
                        }
                    }
                }
            }
        }
    }
    

    //--------Main ListView--------
    ListView {

        id: lvGroups
        anchors {
            top: backet.bottom
            bottom: bottomBar.top
            right: parent.right
            left: parent.left
            leftMargin: 16
            rightMargin: 16
        }
    
        boundsBehavior: Flickable.StopAtBounds
        clip: true
        spacing: 32
        model: groups
    }   // it doesn't need delegate, coz the model is ObjectModel (as told in Documentation)
    

    //--------Function to clear the mainList--------
    function clearList() { groups.clear() } // it's called from Main.qml

    //--------MenuItmInf is a custom property assigned to C++ code--------
    onMenuItmInfChanged: {

        if (menuItmInf=="") return
        var nm = menuItmInf.substring(0, menuItmInf.indexOf('*'));
        var cs = menuItmInf.substring(menuItmInf.indexOf('*')+1, menuItmInf.indexOf('~'))
        var gr = menuItmInf.substring(menuItmInf.indexOf('~')+1, menuItmInf.indexOf('#'))
        var ic = menuItmInf.substring(menuItmInf.indexOf('#')+1, menuItmInf.length)
    
        for (var i=0; i<lvGroups.count; i++)
    

    // if (groups.get(i)===null) continue
    // else

            if (groups.get(i).groupName === gr)
            {
                groups.get(i).addItem(nm,cs,gr,ic)
                return
            }
        groups.append(groupItem.createObject()) // create a new group into Group's list (main list)
        groups.get(lvGroups.count-1).groupName = gr
        groups.get(lvGroups.count-1).addItem(nm,cs,gr,ic)
    }
    

    alt text
    Here is the screenshot: https://ibb.co/Sc2xb1K

    Finally: After refreshing the list (i.e. clearing and reappending items) i'm getting this error:

    W libBTClient.so: qrc:/Itemslist.qml:306: TypeError: Cannot read property 'groupName' of null



  • @Davronito The error is showing at checking the 'groupName' inside the iteration



  • I think I have found the solution)) from this link.
    https://doc.qt.io/qt-5/qtqml-javascript-dynamicobjectcreation.html
    and this link also helped me to understand the error:
    https://stackoverflow.com/questions/45387244/how-to-remove-a-dynamically-created-item-from-column-qml-element
    There was said:
    you should never rely on the garbage collector. It will only work relieably when you use component.createObject(null) and then it will relieably destroy your object at random times, most likely before you want it to be gone, as the reference counting is broken. If it runs to seldomly your application will crash as soon as it runs. If you use component.createObject(someParent) it won't work at all.

    Creating a Component Dynamically
    To dynamically load a component defined in a QML file, call the Qt.createComponent() function in the Qt object. This function takes the URL of the QML file as its only argument and creates a Component object from this URL.

    Once you have a Component, you can call its createObject() method to create an instance of the component. This function can take one or two arguments:

    ->The first is the parent for the new object. The parent can be a graphical object (i.e. of the Item type) or non-graphical object (i.e. of the QtObject or C++ QObject type). Only graphical objects with graphical parent objects will be rendered to the Qt Quick visual canvas. If you wish to set the parent later you can safely pass null to this function.
    ->The second is optional and is a map of property-value ...

    So, my mistake was at creating the group's ItemObject without parent. So I fixed that line as this:

    groups.append(groupItem.createObject(lvGroups)) // create a new group into Group's list (main list)
    

Log in to reply