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. ListView : delay between onRowsRemoved and actual deletion of the delegate
Qt 6.11 is out! See what's new in the release blog

ListView : delay between onRowsRemoved and actual deletion of the delegate

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
3 Posts 2 Posters 1.4k 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.
  • E Offline
    E Offline
    ebatsin
    wrote on last edited by
    #1

    Hi !

    I am using a ListView that displays a model defined in C++ based on a QAbstractListModel.

    Each delegate of the ListView contains a delete button to delete the item in the model on which the delegate is based.

    ListView {
        Connections {
            target: projects
            onRowsRemoved: {
                console.log('the row has been removed in the model')
            }
        }
    
        model: projects
    
        delegate: Item {
            // stuff
    
            Component.onDestruction: {
                console.log('component destroyed')
            }
    
            Button {
                text: 'Delete the ' + project.name + ' project' // each item in the projects model is accessible through 'project'
                onClicked: {
                    projects.remove(project) // remove the current item from the model
                }
            }
        }
    }    
    

    In C++, the method remove(Project *project); is what is called by QML and looks like this :

    void ProjectsModel::remove(Project *project) {
        size_t index = getIndexInModel(project); // returns the index of project in the list
    
        beginRemoveRows(QModelIndex(), index, index);
    
        delete _projects.at(index);
        _projects.removeAt(index);
    
        endRemoveRows();
    }
    

    When I run my program and delete a row by clicking on the button, I get the following output :

    qml: the row has been removed in the model
    qrc:xxx.qml: TypeError: Cannot read property 'name' of undefined
    qml: component destroyed
    

    It seems that there is a delay between the row being removed in the model and the actual removal of the delegate that represent that row. This delay is long enough that it allows the bindings to be processed and the delegate to try to access the content of the item that has already been deleted.

    Since the ViewList aknowledge that the row has been removed (as can be seen with the message logged when the rowsRemoved is received), but do not delete the delegate right away.

    Am I missing something ? I do not really understand why it is possible for a deleted row to still have its delegates bindings processed.

    Any ideas on how to fix this problem ?

    Thanks !

    raven-worxR 1 Reply Last reply
    0
    • E ebatsin

      Hi !

      I am using a ListView that displays a model defined in C++ based on a QAbstractListModel.

      Each delegate of the ListView contains a delete button to delete the item in the model on which the delegate is based.

      ListView {
          Connections {
              target: projects
              onRowsRemoved: {
                  console.log('the row has been removed in the model')
              }
          }
      
          model: projects
      
          delegate: Item {
              // stuff
      
              Component.onDestruction: {
                  console.log('component destroyed')
              }
      
              Button {
                  text: 'Delete the ' + project.name + ' project' // each item in the projects model is accessible through 'project'
                  onClicked: {
                      projects.remove(project) // remove the current item from the model
                  }
              }
          }
      }    
      

      In C++, the method remove(Project *project); is what is called by QML and looks like this :

      void ProjectsModel::remove(Project *project) {
          size_t index = getIndexInModel(project); // returns the index of project in the list
      
          beginRemoveRows(QModelIndex(), index, index);
      
          delete _projects.at(index);
          _projects.removeAt(index);
      
          endRemoveRows();
      }
      

      When I run my program and delete a row by clicking on the button, I get the following output :

      qml: the row has been removed in the model
      qrc:xxx.qml: TypeError: Cannot read property 'name' of undefined
      qml: component destroyed
      

      It seems that there is a delay between the row being removed in the model and the actual removal of the delegate that represent that row. This delay is long enough that it allows the bindings to be processed and the delegate to try to access the content of the item that has already been deleted.

      Since the ViewList aknowledge that the row has been removed (as can be seen with the message logged when the rowsRemoved is received), but do not delete the delegate right away.

      Am I missing something ? I do not really understand why it is possible for a deleted row to still have its delegates bindings processed.

      Any ideas on how to fix this problem ?

      Thanks !

      raven-worxR Offline
      raven-worxR Offline
      raven-worx
      Moderators
      wrote on last edited by
      #2

      @ebatsin
      my first guess would be garbage collection.
      Also just to make sure: You haven't set the ListView.delayRemove attached proeprty right?

      Also where does project come from exactly? How is it instantiated?

      Any ideas on how to fix this problem ?

      see the attached properties/signals of ListView element

      For example, maybe the ListView.remove() signal is emitted earlier than Component.onCompleted.

      --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
      If you have a question please use the forum so others can benefit from the solution in the future

      1 Reply Last reply
      0
      • E Offline
        E Offline
        ebatsin
        wrote on last edited by
        #3

        ListView.delayRemoved is false

        My project list is simply a QList<Project*> _projects;

        To append to it I have the following method :

        void ProjectsModel::append(Project* project) {
            int index = _projects.count();
            
            beginInsertRows(QModelIndex(), index, index);
        
            _projects.insert(index, project);
        
            endInsertRows();
        }
        

        And to access project in QML, my ProjectsModel defines the role project and returns it like this :

        QVariant ProjectsModel::data(QModelIndex const& index, int role = Qt::UserRole) const override {
            // boundary checks
        
            // I do not check the role since I defined only one user role & I always want to return the whole project.
            return QVariant::fromValue(_projects[index.row()]);
        }
        

        I'll look into the order in which the signals are emitted

        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