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

How to filter QListView with a costume ItemDelegate and keeps the filtered Items stored in the list



  • I have QListView which a custom delegate for painting the item in the view, and uses QSortFilterProxyModel for filtering, and QStandardItemModel as the model source.

    Now the requirements are: after when added for example 1000 items, these items are divided into many types such as error, warn, info, debug and which different contents and also date. When want to filter, for example only shows the error items, then after want to show all the item again, but in this place the filtered out items have been deleted from the list, and no longer available.

    So I do not want the items deleted, I want that the items only be hidden from showing, but the items still being present in the list, which when I change the filtering option, it came back.

    How to implement such functionality?

    The second question is when the filtering option has changed, how to notify the list to refresh again, I did not find any function to call the model or list to do so.

    Thanks!!


  • Qt Champions 2017

    There is one example in qt examples directory. Check it.


  • Lifetime Qt Champion

    Hi
    It already works that way.
    All items stay in QStandardItemModel and QSortFilterProxyModel
    will only show the view a subset based on the filer.
    If you change the filter, the view should automatically update.
    Try to look at
    http://doc.qt.io/qt-5/qtwidgets-itemviews-addressbook-example.html

    its filter names.



  • @mrjj Thanks for the reply! Because I am not using the Regex filtering only, so I am unable to update automatically, look to the image below, these are the filtering conditions:

    0_1548002546947_{61F6414D-0D84-4B85-A196-E185D90F5F1D}.png.jpg

    So the sample which is in the Qt documentation is just using Regex, so I cannot call setFilter() function, so in this case, what should I do in case of changing any of the conditions above, the list gets updated.


  • Lifetime Qt Champion

    @BAHRAMUDIN-ADIL
    Ok, so how are you filtering then ?
    Using filterAcceptsRow ?



  • @mrjj Yes, I am extending like this:

    class MyQSortFilterProxyModel : public QSortFilterProxyModel
    

    and implementing the:

    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
    
    bool MyQSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
    {
        QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
        bool result = true;
        int readState = llv->getReadState();
        if(readState > 0) { // if read state was selected
            bool isNew = index.data(LogListItemDelegate::IsNew).toBool();
            result = result&&(readState==1 ? !isNew : isNew); // readState==1 means only read
        }
    
        auto selectedCamera = llv->getSelectedCamera();
        if(std::get<0>(selectedCamera) > 0) { // if camera was selected
             QString title = index.data(LogListItemDelegate::Title).toString();
             result = result && title.contains(std::get<1>(selectedCamera));
        }
    
        int logType = llv->getLOgType();
        if(logType > 0) { // if log type was selected
            int iconType = index.data(LogListItemDelegate::ICON).toInt();
            if(logType == 1) { // info
                result = result && (iconType == 1 || iconType == 9);
            } else if (logType == 2) { // warn
                result = result && (iconType == 2 || iconType == 7);
            } else if (logType == 3) { // error
                result = result && (iconType == 3 || iconType == 6 || iconType == 8);
            }
        }
    
        QString searchWord = llv->getSerchWord();
        if(!searchWord.isEmpty()) {
            QString subtitle = index.data(LogListItemDelegate::DT_Subtitle).toString();
            result = result && subtitle.contains(searchWord);
        }
        return result;
    }
    

  • Lifetime Qt Champion

    Hi
    Ok.
    So when you set the new "filter" (new conditions ) , can you try to call
    http://doc.qt.io/qt-5/qsortfilterproxymodel.html#invalidateFilter
    (in MyQSortFilterProxyModel )
    Maybe invalidate() is enough but docs mentions filterAcceptsRow in doc for invalidateFilter



  • @mrjj Hmmm, but this function is protected, how to call it to form outside? But I called the invalidate() function, but happens nothing?


  • Lifetime Qt Champion

    @BAHRAMUDIN-ADIL
    Hi
    but dont you call some function in MyQSortFilterProxyModel when user press the OK button to
    give it the new parameters ?
    Alternatively, just make a new public function that calls invalidateFilter
    and then call that from outside.



  • @mrjj Yes I know to create a public function by my self and call it from outside and the call this function from inside, I just tried it out, but nothing happens, why it should be like this. In the filterAcceptsRow() I have already checked whether or not to return true, but it still not working as expected?!


  • Lifetime Qt Champion

    @BAHRAMUDIN-ADIL
    Hmm, that is odd.
    I can not guess why it doesn't update. it does for the Qt samples.
    Try to use debugger and see what is going on.

    This example should be close to your code
    http://doc.qt.io/qt-5/qtwidgets-itemviews-customsortfiltermodel-example.html
    and all it does is to call invalidateFilter();

    so maybe its the way how you update its Sort parameters ?



  • @mrjj I am also wondering, I debugged it and when calling the function invalidateFilter(), then filterAcceptsRow() did not get called, usually when called any list validate or updated related function, then the list must reload again and the filterAcceptsRow() function must be called in order to get sync.


Log in to reply