Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. filterAcceptsRow from QSortFilterProxyModel is not called when item state of source model changed
Forum Updated to NodeBB v4.3 + New Features

filterAcceptsRow from QSortFilterProxyModel is not called when item state of source model changed

Scheduled Pinned Locked Moved Solved General and Desktop
16 Posts 4 Posters 2.4k Views
  • 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.
  • Please_Help_me_DP Offline
    Please_Help_me_DP Offline
    Please_Help_me_D
    wrote on last edited by
    #1

    Hi,

    I have custom model H5Model inherited from QAbstractItemModel.
    Some items from this custom model is checkable.
    I display this model in QTreeView_0 but when user check item in this custom model I need to display that item in custom proxy model H5ProxyModel inherited from QSortFilterProxyModel and this custom proxy model I display in QTreeView_1.

    H5ProxyModel.h

    #ifndef H5PROXYMODEL_H
    #define H5PROXYMODEL_H
    
    #include <QSortFilterProxyModel>
    
    
    class H5ProxyModel : public QSortFilterProxyModel
    {
        Q_OBJECT
    public:
        H5ProxyModel(QObject *parent = nullptr);
    
    protected:
        virtual bool filterAcceptsRow(
                int source_row, const QModelIndex &source_parent) const override;
    
    };
    
    #endif // H5PROXYMODEL_H
    

    H5ProxyModel.cpp

    #include "h5proxymodel.h"
    
    #include <h5item.h>
    
    H5ProxyModel::H5ProxyModel(QObject *parent)
    {
    
    }
    
    bool H5ProxyModel::filterAcceptsRow(
            int source_row, const QModelIndex &source_parent) const{
        QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
    
        if (!index.isValid())
            return false;
    
        H5Item *item = static_cast<H5Item*>(index.internalPointer());
        if (item->isRoot())
            return true;
    
        return item->isChecked();
    }
    
    

    But when I change the checkstate of item from source model it doesn't invoke bool H5ProxyModel::filterAcceptsRow().
    Source model works like this when checkstate is changed:

    bool H5Model::setData(const QModelIndex &index, const QVariant &value, int role){
        if (!index.isValid())
            return false;
    
        H5Item *item = getItem(index);
        if (role == Qt::EditRole){
            bool result = item->setData(value.toString());
            emit dataChanged(index, index, {Qt::EditRole});
            return result;
        } else if (role == Qt::DisplayRole){
            bool result = item->setData(value.toString());
            emit dataChanged(index, index, {Qt::DisplayRole});
            return result;
        }  else if (role == Qt::CheckStateRole){
            item->setChecked(value.toBool());
            emit dataChanged(index, index, {Qt::CheckStateRole});
            emit itemStateChanged(item, value.toBool());
            return true;
        }
    
        return false;
    }
    

    f1de28bd-96df-4964-b241-d6af39d0ffe5-image.png

    1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #8

      Your testcase is wrong - you can't simply cast the internal pointer to a QStandardItem. You need

      auto sm = static_cast<QStandardItemModel*>(sourceModel());
      QStandardItem* item = sm->itemFromIndex(index);

      Then it works as expected. The only thing is that the children are only visible when the parent was checked once but this is an implementation problem in your filterAcceptsRow() function.

      btw: setDynamicSortFilter() is not needed as I saw now

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      Please_Help_me_DP 1 Reply Last reply
      2
      • gde23G Offline
        gde23G Offline
        gde23
        wrote on last edited by
        #2

        Have you called invalidate() on the filter after changing the checkstate?

        Please_Help_me_DP 1 Reply Last reply
        1
        • gde23G gde23

          Have you called invalidate() on the filter after changing the checkstate?

          Please_Help_me_DP Offline
          Please_Help_me_DP Offline
          Please_Help_me_D
          wrote on last edited by Please_Help_me_D
          #3

          @gde23 invalidate() is a member of QSortFilterProxyModel
          In my case in first view I display my custom model where I change the checkstate. But when I do this then it doesn't invoke filterAcceptsRow() from my proxy model.

          In the picture above:

          1. in the left view my custom model where I change the checkstate
          2. in the right view my proxy model where should be displayed checked item from left view

          So I don't understand how to use invalidate()

          1 Reply Last reply
          0
          • Christian EhrlicherC Offline
            Christian EhrlicherC Offline
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on last edited by
            #4

            Did you also enable dynamic filtering?

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            Please_Help_me_DP 1 Reply Last reply
            0
            • Christian EhrlicherC Christian Ehrlicher

              Did you also enable dynamic filtering?

              Please_Help_me_DP Offline
              Please_Help_me_DP Offline
              Please_Help_me_D
              wrote on last edited by Please_Help_me_D
              #5

              @Christian-Ehrlicher I just Enabled it but that didn't help... When I change checkstate in left view it doesnt invoke filterAcceptsRow()

              1 Reply Last reply
              0
              • Christian EhrlicherC Offline
                Christian EhrlicherC Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #6

                Please provide a fully minimal and compilable example so we can see what's going wrong.

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                Please_Help_me_DP 1 Reply Last reply
                0
                • Christian EhrlicherC Christian Ehrlicher

                  Please provide a fully minimal and compilable example so we can see what's going wrong.

                  Please_Help_me_DP Offline
                  Please_Help_me_DP Offline
                  Please_Help_me_D
                  wrote on last edited by
                  #7

                  @Christian-Ehrlicher I just created example based on QStandardItemModel(). It just beacause my real model depends on external library. But anyway this example could help me to understand how to "connect" checked items with proxy model
                  Here is the zipped project:
                  https://yadi.sk/d/Kft2dNpTEuTEeQ

                  1 Reply Last reply
                  0
                  • Christian EhrlicherC Offline
                    Christian EhrlicherC Offline
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote on last edited by
                    #8

                    Your testcase is wrong - you can't simply cast the internal pointer to a QStandardItem. You need

                    auto sm = static_cast<QStandardItemModel*>(sourceModel());
                    QStandardItem* item = sm->itemFromIndex(index);

                    Then it works as expected. The only thing is that the children are only visible when the parent was checked once but this is an implementation problem in your filterAcceptsRow() function.

                    btw: setDynamicSortFilter() is not needed as I saw now

                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                    Visit the Qt Academy at https://academy.qt.io/catalog

                    Please_Help_me_DP 1 Reply Last reply
                    2
                    • Christian EhrlicherC Christian Ehrlicher

                      Your testcase is wrong - you can't simply cast the internal pointer to a QStandardItem. You need

                      auto sm = static_cast<QStandardItemModel*>(sourceModel());
                      QStandardItem* item = sm->itemFromIndex(index);

                      Then it works as expected. The only thing is that the children are only visible when the parent was checked once but this is an implementation problem in your filterAcceptsRow() function.

                      btw: setDynamicSortFilter() is not needed as I saw now

                      Please_Help_me_DP Offline
                      Please_Help_me_DP Offline
                      Please_Help_me_D
                      wrote on last edited by
                      #9

                      @Christian-Ehrlicher thank you!
                      Now I'm trying to overcome the thing that children are not displayed if their parent is not checked

                      Christian EhrlicherC 1 Reply Last reply
                      0
                      • Please_Help_me_DP Please_Help_me_D

                        @Christian-Ehrlicher thank you!
                        Now I'm trying to overcome the thing that children are not displayed if their parent is not checked

                        Christian EhrlicherC Offline
                        Christian EhrlicherC Offline
                        Christian Ehrlicher
                        Lifetime Qt Champion
                        wrote on last edited by
                        #10

                        @Please_Help_me_D You have to adjust your filterAcceptRow function to check for the children if one is checked.

                        Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                        Visit the Qt Academy at https://academy.qt.io/catalog

                        Please_Help_me_DP 1 Reply Last reply
                        0
                        • Christian EhrlicherC Christian Ehrlicher

                          @Please_Help_me_D You have to adjust your filterAcceptRow function to check for the children if one is checked.

                          Please_Help_me_DP Offline
                          Please_Help_me_DP Offline
                          Please_Help_me_D
                          wrote on last edited by Please_Help_me_D
                          #11

                          @Christian-Ehrlicher filterAcceptsRow doesn't get called when I check the child from unchecked parent. And when I launch the app all children are UnChecked.
                          Or I misunderstand something?
                          On the picture I checked a child but filterAcceptsRow was not called
                          191998e9-9bfd-4ab7-a94a-a2e303b3fd60-image.png

                          1 Reply Last reply
                          0
                          • Please_Help_me_DP Offline
                            Please_Help_me_DP Offline
                            Please_Help_me_D
                            wrote on last edited by
                            #12

                            I just understood that filterAcceptsRow get invoked only if parent of index is displayed in proxy model. Oherwise proxy model thinks that it is not worth to insert row in proxy model.
                            I can't understand what method of QSortFilterProxyModel I should rewrite to make the proxy to add each checked items regardless of its parent is shown or not.
                            Does anybody know?

                            JonBJ 1 Reply Last reply
                            0
                            • Christian EhrlicherC Offline
                              Christian EhrlicherC Offline
                              Christian Ehrlicher
                              Lifetime Qt Champion
                              wrote on last edited by
                              #13

                              @Please_Help_me_D said in filterAcceptsRow from QSortFilterProxyModel is not called when item state of source model changed:

                              Does anybody know?

                              You can emit a dataChanged() signal for the parents to trigger a recheck.

                              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                              Visit the Qt Academy at https://academy.qt.io/catalog

                              Please_Help_me_DP 1 Reply Last reply
                              0
                              • Please_Help_me_DP Please_Help_me_D

                                I just understood that filterAcceptsRow get invoked only if parent of index is displayed in proxy model. Oherwise proxy model thinks that it is not worth to insert row in proxy model.
                                I can't understand what method of QSortFilterProxyModel I should rewrite to make the proxy to add each checked items regardless of its parent is shown or not.
                                Does anybody know?

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

                                @Please_Help_me_D

                                I just understood that filterAcceptsRow get invoked only if parent of index is displayed in proxy model

                                I truly do not know if the following has any relevance to your situation. But it only takes 5 seconds to try, and you can throw away if it makes no difference.

                                Qt introduced https://doc.qt.io/qt-5/qsortfilterproxymodel.html#recursiveFilteringEnabled-prop. The default is false. Try setting it to true and see whether that causes it to evaluate filterAcceptsRow() against whatever node you are saying it does not currently look at?

                                1 Reply Last reply
                                0
                                • Christian EhrlicherC Christian Ehrlicher

                                  @Please_Help_me_D said in filterAcceptsRow from QSortFilterProxyModel is not called when item state of source model changed:

                                  Does anybody know?

                                  You can emit a dataChanged() signal for the parents to trigger a recheck.

                                  Please_Help_me_DP Offline
                                  Please_Help_me_DP Offline
                                  Please_Help_me_D
                                  wrote on last edited by
                                  #15

                                  @Christian-Ehrlicher I'm thinking about this but I'm trying to avoid sending items that were not changed via dataChanged() signal.
                                  @JonB Yes I've already tried it but this doesn't solve my task. It slightly changes the behaviour of proxy model but not in a way I expect it to be

                                  1 Reply Last reply
                                  1
                                  • Please_Help_me_DP Offline
                                    Please_Help_me_DP Offline
                                    Please_Help_me_D
                                    wrote on last edited by
                                    #16

                                    I decided to make the following:
                                    I'm going to make all the items (except the root) checkable. When I change checkstate of a item to Qt::Checked then this item also changes checkState of its parent to Qt::PartiallyChecked.
                                    So this chain should work but I have not finished it yet

                                    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