Why binding to MyAbstractItemModel.rowCount does not work?



  • Hi

    I have this ListView with pictures, sometimes when there are no pictures in the model, I want the ListView to have width and height set to 0, so I have used binding to width and height but it does not work. As a workaround I have used onCountChanged to recalculate ListView width and height. My model calls functions like beginInsertRows so why this binding does not work?

    ListView {
        id: plantPicView
        snapMode: ListView.SnapOneItem
        highlightRangeMode: ListView.StrictlyEnforceRange
        orientation: Qt.Horizontal
        width:(PictureModel.rowCount() ? parent.width : 0)
        height:(PictureModel.rowCount() ? 3*width/4 : 0)
        anchors.horizontalCenter: parent.horizontalCenter
        clip: true
        z:10
    
    
        model: PictureModel            
        delegate: PictureDelegate {
            z:11
            source: pic_name_role
        }
        spacing: 0
    
        onCountChanged: {
            console.log("plantPicView count:"+count)
            width=(PictureModel.rowCount() ? parent.width : 0)
            height=(PictureModel.rowCount() ? 3*width/4 : 0)
        }
    }
    //piece of model code
    void PictureModel::setCatalogId(int catalog_id) {
      //  beginResetModel();
        if(picMap.count()) {
            beginRemoveRows(QModelIndex(), 0, picMap.count()-1);
            QMapIterator<int,PictureModelDataStruct*> i(picMap);
            while(i.hasNext()) {
                i.next();
                delete i.value();
            }
            picMap.clear();
            endRemoveRows();
        }
        int row=0;
        QList<int> list=catalogData->getPicList(catalog_id);
        for(int i=0;i<list.count();i++) {
            PictureModelDataStruct *p=new PictureModelDataStruct;
            p->pic_id=list.at(i);
            p->row=row;
            p->fileName=QString("images/%1.jpg").arg(p->pic_id);
            p->available=1;
            picMap.insert(p->row,p);
            beginInsertRows(QModelIndex(), row, row);
            endInsertRows();
            row++;
            qDebug()<<"PictureModel::setCatalogId fileName:"<<p->fileName;
        }
     //   endResetModel();
    }
    

    Best Regards
    Marek



  • @Marek width:(PictureModel.rowCount() ? parent.width : 0) is wrong, you can't bind to a function. It's evaluated only once when the binding is created.

    If you want it to be simple in QML but complicated in C++ you have to write your own property to the class which is used in the QML binding. If you want it to be complicated in QML but simple in C++ you have to write signal handlers in QML for existing rowsInserted and rowsRemoved C++ signals (or your own countChanged as you apparently have done).

    Maybe the former is what you want. Use Q_PROPERTY with 'changed' signal (see the examples in the Qt docs) and emit that signal when the row count is changed in C++. Then you can use that property in QML bindings, and the value is re-evaluated automatically when the signal is sent.



  • @Eeli-K thanks ;)

    So in short words, don't bind to function as this is evaluated only once when binding is created, instead bind to property and send signal when property has changed. Corrected example below

    ListView {
        id: plantPicView
        snapMode: ListView.SnapOneItem
        highlightRangeMode: ListView.StrictlyEnforceRange
        orientation: Qt.Horizontal
        width:(PictureModel.rows ? parent.width : 0)
        height:(PictureModel.rows ? 3*width/4 : 0)
        anchors.horizontalCenter: parent.horizontalCenter
        clip: true
        z:10
    
    
        model: PictureModel
        delegate: PictureDelegate {
            z:11
            source: pic_name_role
        }
        spacing: 0
    }
    //part of model.h code
    class PictureModel : public QAbstractListModel
    {
        Q_OBJECT
    public:
        Q_PROPERTY(int rows MEMBER m_rows NOTIFY rowsChanged)
    
    //part of model.cpp code
    void PictureModel::setCatalogId(int catalog_id) {
        if(picMap.count()) {
            beginRemoveRows(QModelIndex(), 0, picMap.count()-1);
            QMapIterator<int,PictureModelDataStruct*> i(picMap);
            while(i.hasNext()) {
                i.next();
                delete i.value();
            }
            picMap.clear();
            endRemoveRows();
        }
        int row=0;
        QList<int> list=catalogData->getPicList(catalog_id);
        for(int i=0;i<list.count();i++) {
            PictureModelDataStruct *p=new PictureModelDataStruct;
            p->pic_id=list.at(i);
            p->row=row;
            p->fileName=QString("images/%1.jpg").arg(p->pic_id);
            p->available=1;
            picMap.insert(p->row,p);
            beginInsertRows(QModelIndex(), row, row);
            endInsertRows();
            row++;
            qDebug()<<"PictureModel::setCatalogId fileName:"<<p->fileName;
        }
        m_rows=picMap.count();
        emit rowsChanged();
    }
    


  • @Marek Looks like what I meant. One clarification to my comment: the whole binding expression is evaluated when a property used in that expression is changed; in your original code it was evaluated once, in other cases it may be evaluated more often, but the function call itself (like getSomeProperty()) can't trigger a binding re-evaluation.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.