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

ListView issue when updated (current index set to 0)



  • Hi all,
    I meet an issue with listView when the model is updated from C++.
    After each update from C++, the current index is set to 0 and the view return to beginning of it !
    In the C++ side, the model exposed is declared like this :

    Q_PROPERTY(QList<QObject*> debugList READ getDebugList NOTIFY debugListChanged)
    

    in qml :

     Component {
                        id: nameDelegate
                        Item {
                            id: delegateItem
                            height: ListView.isCurrentItem ? 25 : textDebug.height
                            width:debugRx.width
                            Behavior on height {
                                NumberAnimation {
                                    duration: 750
                                    easing.type: "InOutQuint"
                                }
                            }
                            Text {
                                id:textDebug
                                text: model.modelData.data
                                color: model.modelData.color
                                width: debugRx.width
                                //height: 20
                                lineHeight: 15
                                lineHeightMode:  Text.FixedHeight
                                scale: parent.height/height
                                transformOrigin: Item.Left
                                wrapMode: Text.WordWrap
                                font{
                                    family: "arial"
                                    pixelSize:16
                                }
                            }
                        }
                    }
    
                    ListView {
                        id:listViewDebug
                        snapMode: ListView.SnapOneItem
                        property string name: "listeDebug"
                        property bool scrollDebugAuto: true
                        property int scrollDebugIndex: 0
                        bottomMargin: 5
                        anchors.fill: parent
                        anchors.topMargin: 5
                        anchors.bottomMargin: 5
                        anchors.leftMargin: 2
                        anchors.rightMargin: 2
                        clip:true
                        model:device.debugList
                        focus:true
                        delegate: nameDelegate
                        ScrollBar.vertical: ScrollBar{
                            id:scrollBarDebug
                        }
    
                        highlight: Rectangle {
                            width: listViewDebug.width;
                            border.color: "gray"
                            border.width: 2
                            color : "green"
                            opacity: 0.3
                            radius:5
                            Behavior on y {
                                SpringAnimation {
                                    spring: 3
                                    damping: 0.2
                                }
                            }
                        }
                        highlightFollowsCurrentItem: true
                        //highlightRangeMode : ListView.StrictlyEnforceRange
                        currentIndex: scrollDebugAuto ? listViewDebug.count-1 : scrollDebugIndex
                        onCurrentIndexChanged:{
                            console.log("current index update :"+currentIndex)
                        }
                        onModelChanged: {
                            console.log("current index :"+currentIndex);
                            console.log("save index : "+scrollDebugIndex)
                        }
                        Component.onCompleted: positionViewAtIndex(count - 1, ListView.Beginning)
    
                    }
                }
    

    When the property scrollDebugAuto is true it work fine (the view stay et end of the listView) but when it false the view goes to beginning (current index : 0)
    false--> i 'm trying to add a functionality to disable the list update continuously when the user click to a button

                    CheckBox {
                        id: checkBox
                        text: "\uf0c1"
                        checked: true
                        onCheckedChanged:
                        {
                            if(checked)
                                listViewDebug.scrollDebugAuto=true
                            else
                            {
                                listViewDebug.scrollDebugAuto=false
                                listViewDebug.scrollDebugIndex=listViewDebug.count-1
                                console.log("scroll debug index : "+listViewDebug.scrollDebugIndex)
                            }
                        }
                    }
    

    That's strange is when the model is updated from C++, the listView index is set to 0 !
    When the scrollDebugAuto is true i have this on the log :

    qml: current index update :52
    qml: current index update :0
    qml: current index update :52
    qml: current index :53
    qml: save index : 0

    when is false

    qml: current index update :0
    qml: current index :89
    qml: save index : 72

    we can see that the current index is set to 0 during C++ model update .
    Do you have an idea how i can resolve this ?



  • @Mickael-22 said in ListView issue when updated (current index set to 0):

    Do you have an idea how i can resolve this ?

    AFAIK, this is the normal behavior when using QList<Object *>() or QStringList() as model, because each model update will generate a full new model.
    If you wan't a smooth update, you have to use QAbstractItemModel, cf. https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html



  • @KroMignon Thanks for this explanations, it's more clear now.
    I will have a look on QAbstractItemModel class, it just pity to add more complexity with this class to just keep list current index to it's value !



  • @Mickael-22 Yes QAbstractItemModel is not easy to use.

    I use since many years now a template class create by Thomas Boutroue which creates an QAbstractListModel by introspection of the base QObject.
    Take a look at Qt QML Models and Qt SuperMacros.

    Here are some explanations at Qt World Summit 2015:
    https://resources.qt.io/videos/qtws15-lightning-talk-a-new-way-for-creating-qml-models-from-c-thomas-boutroue

    Perhaps this could help you.



  • This is an undocumented behavior of ListView. When the model is changed, currentIndex is set to 0, or -1 if the model if the empty.

    https://code.woboq.org/qt5/qtdeclarative/src/quick/items/qquickitemview.cpp.html#239:

    if (d->model) {
            ...
            if (isComponentComplete()) {
                ...
                setCurrentIndex(d->model->count() > 0 ? 0 : -1);
    

    If you have the option, updating the model rather than changing to a new one is probably a better method.



  • @KroMignon Thanks a lot !

    @jeremy_k
    in the C++ code i just emit a signal that the list changed like this :

        m_debugList.append(new BleData(data,color,this));
        emit debugListChanged();
    
    class BleData : public QObject
    {
        Q_OBJECT
    
    public:
        explicit BleData(QObject *parent = nullptr);
        BleData(QString data,QString color = "black",QObject *parent = nullptr);
    
        Q_PROPERTY(QString data READ getData NOTIFY dataChanged)
        Q_PROPERTY(QString color READ getColor NOTIFY colorChanged)
    
    signals:
    
        void dataChanged(QString data);
        void colorChanged(QString color);
    
    public slots:
        QString getData() const;
        QString getColor() const;
        void addData(QString data,QString color="black");
    
    private :
        QString m_data;
        QString m_color;
    };
    

    I don't know how to proceed in another way



  • @Mickael-22 said in ListView issue when updated (current index set to 0):

    @KroMignon Thanks a lot !

    @jeremy_k
    in the C++ code i just emit a signal that the list changed like this :

        m_debugList.append(new BleData(data,color,this));
        emit debugListChanged();
    

    That's the entire problem. Emitting the change signal for the list of QObjects says the entire list has changed, and should be treated as a new model.

    The item models that @KroMignon refers to have signals to indicate changes within the model. If implementing a new QAbstractItemModel sounds like too much work, using a QStandardItemModel, or a QML ListView might work. QStringListView could also, with some changes to the delegate.



  • Thanks for this precisions.
    i will have a look on the different options and let you know the more convenient way i will use


Log in to reply