Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Why binding to MyAbstractItemModel.rowCount does not work?

Why binding to MyAbstractItemModel.rowCount does not work?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
4 Posts 2 Posters 1.6k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Marek
    wrote on last edited by
    #1

    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

    E 1 Reply Last reply
    0
    • M Marek

      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

      E Offline
      E Offline
      Eeli K
      wrote on last edited by
      #2

      @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.

      M 1 Reply Last reply
      1
      • E Eeli K

        @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.

        M Offline
        M Offline
        Marek
        wrote on last edited by
        #3

        @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();
        }
        
        E 1 Reply Last reply
        0
        • M Marek

          @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();
          }
          
          E Offline
          E Offline
          Eeli K
          wrote on last edited by
          #4

          @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.

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved