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. Smarter way to get a list of children in Tree Model
QtWS25 Last Chance

Smarter way to get a list of children in Tree Model

Scheduled Pinned Locked Moved Unsolved General and Desktop
modelproxy
5 Posts 3 Posters 4.5k 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.
  • V Offline
    V Offline
    VRonin
    wrote on 23 Sept 2016, 17:30 last edited by VRonin
    #1

    Hi guys, I'm being lazy here. Do you know of any Proxy model that shows only a certain level of a tree as a list?

    What I need is to turn something like

    • Item 1
      • Item 2
      • Item 3
    • Item 4
      • Item 5

    into:
    when level property is 0

    • Item 1
    • Item 4

    when level property is 1

    • Item 2
    • Item 3
    • Item 5

    I achieved it already using 3 proxies concatenated but wanted to know if there is a 1 proxy way already available.

    My current solution:

    #include <QIdentityProxyModel>
    
    class LevelDataProxy : public QIdentityProxyModel
    {
        Q_OBJECT
    
    public:
        explicit LevelDataProxy(QObject *parent = nullptr) : QIdentityProxyModel(parent) {}
        enum {
            LevelDataRole = 1989
        };
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override{
        if (index.isValid() && role == LevelDataRole) {
            Q_ASSERT(checkIndex(index));
            int result = 0;
            for (QModelIndex cursor(index); cursor.parent().isValid(); cursor = cursor.parent(), ++result) {}
            return result;
        }
        return QIdentityProxyModel::data(index, role);
    }
    };
    
    

    and then I use it and a QSortFilterProxyModel with a KDescendantsProxyModel in the middle:

        // QAbstractItemModel* originalModel;
        LevelDataProxy* levelInfoProxy = new LevelDataProxy(&printSettingDialog);
        levelInfoProxy->setSourceModel(originalModel);
        KDescendantsProxyModel* flatModel = new KDescendantsProxyModel(&printSettingDialog);
        flatModel->setSourceModel(levelInfoProxy);
        flatModel->setDisplayAncestorData(false);
        QSortFilterProxyModel* levelInfoFilter = new QSortFilterProxyModel(&printSettingDialog);
        levelInfoFilter->setFilterRole(LevelDataProxy::LevelDataRole);
        levelInfoFilter->setFilterFixedString("1");
        levelInfoFilter->setSourceModel(flatModel);
    

    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
    ~Napoleon Bonaparte

    On a crusade to banish setIndexWidget() from the holy land of Qt

    K 1 Reply Last reply 24 Sept 2016, 13:01
    1
    • P Offline
      P Offline
      p3c0
      Moderators
      wrote on 24 Sept 2016, 05:32 last edited by
      #2

      @VRonin
      How about re-implementing filterAcceptsRow in QSortFilterProxyModel and return true or false depending upon source_parent ? For eg. Item 1 and Item 4 has invisible root as their parent but the their children don't.
      Just a non educated guess. Haven't tried myself.

      157

      V 1 Reply Last reply 24 Sept 2016, 13:43
      0
      • V VRonin
        23 Sept 2016, 17:30

        Hi guys, I'm being lazy here. Do you know of any Proxy model that shows only a certain level of a tree as a list?

        What I need is to turn something like

        • Item 1
          • Item 2
          • Item 3
        • Item 4
          • Item 5

        into:
        when level property is 0

        • Item 1
        • Item 4

        when level property is 1

        • Item 2
        • Item 3
        • Item 5

        I achieved it already using 3 proxies concatenated but wanted to know if there is a 1 proxy way already available.

        My current solution:

        #include <QIdentityProxyModel>
        
        class LevelDataProxy : public QIdentityProxyModel
        {
            Q_OBJECT
        
        public:
            explicit LevelDataProxy(QObject *parent = nullptr) : QIdentityProxyModel(parent) {}
            enum {
                LevelDataRole = 1989
            };
            QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override{
            if (index.isValid() && role == LevelDataRole) {
                Q_ASSERT(checkIndex(index));
                int result = 0;
                for (QModelIndex cursor(index); cursor.parent().isValid(); cursor = cursor.parent(), ++result) {}
                return result;
            }
            return QIdentityProxyModel::data(index, role);
        }
        };
        
        

        and then I use it and a QSortFilterProxyModel with a KDescendantsProxyModel in the middle:

            // QAbstractItemModel* originalModel;
            LevelDataProxy* levelInfoProxy = new LevelDataProxy(&printSettingDialog);
            levelInfoProxy->setSourceModel(originalModel);
            KDescendantsProxyModel* flatModel = new KDescendantsProxyModel(&printSettingDialog);
            flatModel->setSourceModel(levelInfoProxy);
            flatModel->setDisplayAncestorData(false);
            QSortFilterProxyModel* levelInfoFilter = new QSortFilterProxyModel(&printSettingDialog);
            levelInfoFilter->setFilterRole(LevelDataProxy::LevelDataRole);
            levelInfoFilter->setFilterFixedString("1");
            levelInfoFilter->setSourceModel(flatModel);
        
        K Offline
        K Offline
        kshegunov
        Moderators
        wrote on 24 Sept 2016, 13:01 last edited by
        #3

        Another speculative suggestion:
        I don't really like the idea of deriving from the identity proxy and then overriding data(), somehow feels wrong. You want to change the structure, not the data. What I'd try if I were you, is to subclass QAbstractProxyModel and do that depth-search like thingy only once, to obtain a QModelIndex for the "parent". After that in the index* methods (especially relevant seems hasIndex()) I'd return invalid model indexes for items that aren't parented to the parent I've stored in the beginning.

        I hope that helps.
        Kind regards.

        Read and abide by the Qt Code of Conduct

        1 Reply Last reply
        0
        • P p3c0
          24 Sept 2016, 05:32

          @VRonin
          How about re-implementing filterAcceptsRow in QSortFilterProxyModel and return true or false depending upon source_parent ? For eg. Item 1 and Item 4 has invisible root as their parent but the their children don't.
          Just a non educated guess. Haven't tried myself.

          V Offline
          V Offline
          VRonin
          wrote on 24 Sept 2016, 13:43 last edited by
          #4

          @p3c0 Most views would hide all children if the parent is hidden so you won't be able to achieve a list of children

          @kshegunov the overridden data is to store somewhere the level in the original tree before it gets flattened by KDescendantsProxyModel. I know it's ugly and dirty that's why I asked the question. The second part seems pretty much the way to go but since this I need this just to show a combobox I didn't feel like going through building a QAbstractProxyModel from scratch

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          K 1 Reply Last reply 24 Sept 2016, 13:56
          0
          • V VRonin
            24 Sept 2016, 13:43

            @p3c0 Most views would hide all children if the parent is hidden so you won't be able to achieve a list of children

            @kshegunov the overridden data is to store somewhere the level in the original tree before it gets flattened by KDescendantsProxyModel. I know it's ugly and dirty that's why I asked the question. The second part seems pretty much the way to go but since this I need this just to show a combobox I didn't feel like going through building a QAbstractProxyModel from scratch

            K Offline
            K Offline
            kshegunov
            Moderators
            wrote on 24 Sept 2016, 13:56 last edited by kshegunov
            #5

            @VRonin said in Smarter way to get a list of children in Tree Model:

            the overridden data is to store somewhere the level in the original tree before it gets flattened by KDescendantsProxyModel.

            I don't believe you need that. Pushing a tree model to a list/table view should give you list/table with the root-level items (speculation again!). In my mind it should be just enough to "move" the root of the model before giving it to the view.

            I didn't feel like going through building a QAbstractProxyModel from scratch

            Well, yes, I can see why, but if you think about it, most of your methods should turn out trivial (more or less) - similarly to the identity proxy model.

            Kind regards.

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            0

            2/5

            24 Sept 2016, 05:32

            • Login

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