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. QSortFilterProxyModel filterAcceptsRow being called unexpectedly
Qt 6.11 is out! See what's new in the release blog

QSortFilterProxyModel filterAcceptsRow being called unexpectedly

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
13 Posts 3 Posters 3.4k Views 2 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.
  • SGaistS Offline
    SGaistS Offline
    SGaist
    Lifetime Qt Champion
    wrote on last edited by
    #4

    Your are accessing items_ quite a lot of time for nothing. The data method is called many times because there are lots of roles. Since you only return data for Role1 and Role2, ensure first that it's one of them and then load the data.

    Interested in AI ? www.idiap.ch
    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

    W 1 Reply Last reply
    1
    • SGaistS SGaist

      Your are accessing items_ quite a lot of time for nothing. The data method is called many times because there are lots of roles. Since you only return data for Role1 and Role2, ensure first that it's one of them and then load the data.

      W Offline
      W Offline
      wagner2x
      wrote on last edited by
      #5

      @SGaist

      are you basically saying that I should change it to something like this?

      QVariant CustomList::data(int index, int role)
      {
          QVariantMap entry;
          switch (role) {
          case myRole1:
              entry = items_.at(index);
              return QVariant::fromValue(entry["myRole1"]);
          case myRole2:
              entry = items_.at(index);
              return QVariant::fromValue(entry["myRole2"]);
      
          default:
              // should be unreachable code
              return QVariant();
          }
      }
      
      JonBJ 1 Reply Last reply
      0
      • W wagner2x

        @SGaist

        are you basically saying that I should change it to something like this?

        QVariant CustomList::data(int index, int role)
        {
            QVariantMap entry;
            switch (role) {
            case myRole1:
                entry = items_.at(index);
                return QVariant::fromValue(entry["myRole1"]);
            case myRole2:
                entry = items_.at(index);
                return QVariant::fromValue(entry["myRole2"]);
        
            default:
                // should be unreachable code
                return QVariant();
            }
        }
        
        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #6

        @wagner2x Yes.

        W 1 Reply Last reply
        0
        • JonBJ JonB

          @wagner2x Yes.

          W Offline
          W Offline
          wagner2x
          wrote on last edited by
          #7

          @JonB

          The Data function gets called for Roles other than the ones I defined?

          JonBJ 1 Reply Last reply
          0
          • W wagner2x

            @JonB

            The Data function gets called for Roles other than the ones I defined?

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by
            #8

            @wagner2x
            Is that a question or an observation? Yes indeed it does, many more. Basically for most of the defined ones (what font? what color? what alignment?). @SGaist is suggesting therefore you only evaluate items_.at(index) when absolutely necessary.

            If you were to have a lot of roles required in the switch statement one could factor out the items_.at(index) retrieval to one place if you wish and some common expression for QVariant::fromValue(entry["myRole..."]) to cut down on code if that's what you mean.

            W 1 Reply Last reply
            0
            • JonBJ JonB

              @wagner2x
              Is that a question or an observation? Yes indeed it does, many more. Basically for most of the defined ones (what font? what color? what alignment?). @SGaist is suggesting therefore you only evaluate items_.at(index) when absolutely necessary.

              If you were to have a lot of roles required in the switch statement one could factor out the items_.at(index) retrieval to one place if you wish and some common expression for QVariant::fromValue(entry["myRole..."]) to cut down on code if that's what you mean.

              W Offline
              W Offline
              wagner2x
              wrote on last edited by
              #9

              @JonB

              That was question :P I should have realized that! That makes sense. I made that minor change but still am seeing significant delays in evaluating the filter after the source model has changed.

              In the original post I described Model C and Model D as QSortFilterProxyModels which basically are to distinguish Items that have been selected or not. After I set the new source, Model C and Model D both reevaluate their filter (which makes sense) but if there are many elements that pass the filter, this operations is taking a while. Any ideas why that may be? Like I meantioned...there are only 300 items in the list total.

              Here is my filterAcceptsRow Function...It seems pretty straight forward but I could be doing something wrong:

              bool UnselectedProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
              {
                  QModelIndex itemIndex = sourceModel()->index(source_row, 0, source_parent);
                  if(itemIndex.isValid() && !source_parent.isValid())
                  {
                      return !itemIndex.data(selected).toBool();
                  }
                  return false;
              }
              

              Remember this takes Model E (a QIdentityProxyModel) as its source where the source of Model E is swapped in and out by user selections on the filter.

              W 1 Reply Last reply
              0
              • W wagner2x

                @JonB

                That was question :P I should have realized that! That makes sense. I made that minor change but still am seeing significant delays in evaluating the filter after the source model has changed.

                In the original post I described Model C and Model D as QSortFilterProxyModels which basically are to distinguish Items that have been selected or not. After I set the new source, Model C and Model D both reevaluate their filter (which makes sense) but if there are many elements that pass the filter, this operations is taking a while. Any ideas why that may be? Like I meantioned...there are only 300 items in the list total.

                Here is my filterAcceptsRow Function...It seems pretty straight forward but I could be doing something wrong:

                bool UnselectedProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
                {
                    QModelIndex itemIndex = sourceModel()->index(source_row, 0, source_parent);
                    if(itemIndex.isValid() && !source_parent.isValid())
                    {
                        return !itemIndex.data(selected).toBool();
                    }
                    return false;
                }
                

                Remember this takes Model E (a QIdentityProxyModel) as its source where the source of Model E is swapped in and out by user selections on the filter.

                W Offline
                W Offline
                wagner2x
                wrote on last edited by wagner2x
                #10

                Now looking at it I don't think it is the filtering that is taking forever...I think it is the DRAW after the model change has completed. I am going to try implementing lazy loading on my model and see if that helps with this.

                1 Reply Last reply
                0
                • W Offline
                  W Offline
                  wagner2x
                  wrote on last edited by wagner2x
                  #11

                  How does Lazy Loading work if you have a chain of models like I have? Do I need to reimplement canFetchmore and FetchMore for all of the models in the chain? Also, any ideas on what could make a ListView QML widget take forever to draw when its model gets switched?

                  1 Reply Last reply
                  0
                  • W Offline
                    W Offline
                    wagner2x
                    wrote on last edited by
                    #12

                    @SGaist

                    I tried implementing canFetchMore and fetchMore on Models C and D but am seeing a QT error

                    QDeclarativeComponent: Cannot create new component instance before completing the previous
                    <Unknown File>: QML VisualDataModel: Error creating delegate

                    I am trying to batch 10 delegates at a time:

                    bool UnselectedModel::canFetchMore(const QModelIndex &parent) const
                    {
                        if (parent.isValid())
                                return false;
                        //I should be able to use rowCount here right? This should be executed after filteracceptsRow is finished?
                        return (itemsFetched_ < rowCount());
                    }
                    
                    void UnselectedModel::fetchMore(const QModelIndex &parent)
                    {
                        if (parent.isValid())
                                return;
                            int remainder = rowCount() - itemsFetched_;
                            int itemsToFetch = qMin(10, remainder);
                            if (itemsToFetch <= 0)
                                return;
                            beginInsertRows(QModelIndex(), itemsFetched_, itemsFetched_ + itemsToFetch - 1);
                    
                            itemsFetched_ += itemsToFetch;
                    
                            endInsertRows();
                            emit numberPopulated(itemsToFetch);
                    }
                    

                    I also clear the itemsFetched_ member every time we make a sourceModel change on Model E. Do I need to reset Model C and D when the source model changes if I am implementing fetchMore?

                    1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #13

                      Can you provide a minimal compilable example of your code ?

                      That would help take a better look at your situation ?

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      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