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. [solved]QTreeView : Child-indicator is not updated after inserting children

[solved]QTreeView : Child-indicator is not updated after inserting children

Scheduled Pinned Locked Moved General and Desktop
13 Posts 4 Posters 12.7k 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.
  • M Offline
    M Offline
    Mario84
    wrote on last edited by
    #1

    This is my second post in a few minutes :)
    ...and the problem is similar the the one from my first post: http://qt-project.org/forums/viewthread/18504/
    I guess that the solution could be the same, but the situation is different:

    I am developing a TreeView (for a Usermanagement, groups are nodes, users are childs) in which it is possible
    to dynamically add TreeItems to other TreeItems (as children).
    I call beginInsertRows before and endInsertRows after creating the new Items. In standard-cases eveything seems to work fine, as long as the parentitem I am adding children to already has children. If the new inserted items are the first ones, they are also correctly inserted into my underlying data-structure, but the parentitemin the treeview does not update its branch/child-indicator.
    So it looks like there was nothing added. I have to rebuild my whole tree (via reset()) to make the changes visible...
    (I guess it will be the same when I remove the last items and the childindicator should diappear, but my implementation isn't finished, so I have no possibility to test this second case)

    Can someone tell me how I can advise the TreeView to update correctly without updating everything (by calling reset())??

    1 Reply Last reply
    0
    • JeroentjehomeJ Offline
      JeroentjehomeJ Offline
      Jeroentjehome
      wrote on last edited by
      #2

      I would think you need to emit the datachanged signal of the parent and not only of the child you inserted.
      This is from the mind....can check the books if needed.
      greetz

      Greetz, Jeroen

      1 Reply Last reply
      0
      • M Offline
        M Offline
        Mario84
        wrote on last edited by
        #3

        I've already tried this one (and tried it again after I read your answer ;) , but unfortunately this doesn't help.
        As far as I know, dataChanged affects only the data of a treeitem (e.g. the displayed text, icons...), that means, everything that is queried through QAbstractItemModel::data()... but the branch-indicator is not part of the itemdata, but of the treestructure, and so dataChanged() has no effect on it...

        The only idea I have left, is removing and re-inserting the parentnode... but I'm sure there must be a better (and more performant) way to update the indicator.

        1 Reply Last reply
        0
        • M Offline
          M Offline
          Mario84
          wrote on last edited by
          #4

          Ok, I found a solution, but I think this is some kind of bug...

          I inserted the child as follows:
          @beginInsertRows(index, pItem->childrenCount(), pItem->childrenCount()); //index is the index of pItem, which is the parent I'm inserting to
          new CTreeItem(pData, pItem);
          endInsertRows();@
          This should insert the new Item after the last child of pItem, and it does so when there are already children, if childrenCount() is 0 nothing happens. This is a bug in my opinion, because according to the documentation of QAbstractItemModel::beginInsertRows() the first item has index 0 and the parameter first specifies the new child-index my item will have (which should be 0 when it is the first item)

          Please correct me if I'm wrong... (Or tell me that I'm right ;)

          Anyway, I fortunately use a QSortFilterProxyModel, so I do not have to care about the child-order in my model... now I'm just calling beginInsertRows(index, 1, 1) no matter if index already has children or not, and it works...

          1 Reply Last reply
          0
          • G Offline
            G Offline
            goetz
            wrote on last edited by
            #5

            If you use

            @
            beginInsertRows(index, pItem->childrenCount(), pItem->childrenCount());
            @

            then, with a parent item pItem without children, this literally translates to

            @
            beginInsertRows(index, 0, 0);
            @

            so, actually you're telling your model that you are going to insert zero items. I would call no update on the parent item as the correct reaction of the model to that :-)

            http://www.catb.org/~esr/faqs/smart-questions.html

            1 Reply Last reply
            0
            • M Offline
              M Offline
              Mario84
              wrote on last edited by
              #6

              But then the documentation on that is a bit confusing... because it says the two ints are the positions of the new items...

              From QAbstractItemModel::beginInsertRows()-documentation:
              @The parent index corresponds to the parent into which the new rows are inserted; first and last are the row numbers that the new rows will have after they have been inserted.@

              ...and if there aren't already items, the new one has of course position 0.
              Which for my understanding means that beginInsertRows(index, 0, 0); should insert the new item at position 0, and because the last position is also 0, there's only one inserted.
              If this is interpreted as a count, it's a "bug" in the doc ;)

              btw:
              When I call beginInsertRows(index, 1, 1); it does work, but I get the debug message "QSortFilterProxyModel: invalid inserted rows reported by source model", so there has to be a better solution...

              1 Reply Last reply
              0
              • G Offline
                G Offline
                goetz
                wrote on last edited by
                #7

                Oh, you're right, of course. I didn't read the docs and stand corrected here.

                It looks a bit weird, though. I don't have problems with that in my own models, it works as expected.

                Do methods hasChildren() and rowCount() on the parent index return the correct values afterwards?

                Maybe it can help to set the parent expanded, using slot expand().

                http://www.catb.org/~esr/faqs/smart-questions.html

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  Mario84
                  wrote on last edited by
                  #8

                  I already tried expanding the parent, without any effect.
                  When I query hasChildren() and rowCount() on the index used as parent in beginInsertRows immediately after endInsertRows rowCount() returns 1, and hasChildren() returns true...

                  edit:
                  it still returns 1 and true when i call the non-updating version beginInsertRows(index, pItem->childrenCount(), pItem->childrenCount())... (and no debug message in this case)

                  1 Reply Last reply
                  0
                  • G Offline
                    G Offline
                    goetz
                    wrote on last edited by
                    #9

                    Can you create a small, self contained test case? It's hard to help further without the "working" failure.

                    http://www.catb.org/~esr/faqs/smart-questions.html

                    1 Reply Last reply
                    0
                    • M Offline
                      M Offline
                      Mario84
                      wrote on last edited by
                      #10

                      [quote author="Volker" date="1343338405"]Can you create a small, self contained test case? It's hard to help further without the "working" failure.[/quote]

                      Lol... I already tried to create a small test-project containing the error for posting it here, but I didn't get the error again :D
                      I'll give it another try this weekend...

                      But in the meantime we found out that the error is somehow related to the SortFilterProxyModel I use:
                      if I do not use this ProxyModel, everything works fine (without sorting and filtering of course)
                      In this ProxyModel I overwrite lessThan() and filterAcceptsRow(), and call setDynamicSortFilter(true) in the constructor... thats all it does.

                      That's the code of my ProxyModel (shortened):
                      @
                      MySortModel::MySortModel(QObject *pParent)
                      : QSortFilterProxyModel(pParent)
                      {
                      setDynamicSortFilter(true);
                      c_pDataSource = NULL;
                      }

                      //Needed for comparisons in lessThan and filterAcceptsRow
                      void MySortModel::setUserData(MyDataManagingClass *pDataSource)
                      {
                      c_pDataSource = pDataSource;
                      }

                      bool MySortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
                      {
                      MyTreeItem *pLeftItem;
                      MyTreeItem *pRightItem;

                      pLeftItem = static_cast<MyTreeItem*>(left.internalPointer());
                      pRightItem = static_cast<MyTreeItem*>(right.internalPointer());

                      if (!pLeftItem || !pRightItem)
                      {
                      return false;
                      }

                      //Do some comparisons and return true or false...
                      }

                      bool MySortModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
                      {
                      MyTreeItem *pItem;
                      int iColumn;
                      QRegExp qrFilter;

                      iColumn = filterKeyColumn();
                      qrFilter = filterRegExp();

                      if (qrFilter.isEmpty() || !qrFilter.isValid())
                      {
                      //No filter, show all
                      return true;
                      }

                      //Get Item to filter
                      if (!source_parent.isValid())
                      {
                      //pItem is Top-Level
                      pItem = static_cast<MyTreeItem*>((static_cast<MyModel*>(sourceModel()))->getBufferRoot()->getChild(source_row));
                      }
                      else
                      {
                      //pItem is Child
                      pItem = (static_cast<MyTreeItem*>(source_parent.child(source_row, 0).internalPointer()));
                      }

                      if (!pItem)
                      {
                      return true;
                      }

                      //Do some comparisons to determine if pItem is displayed and return true or false...
                      }
                      @

                      in the class creating the QTreeView I do the following (again shortened):

                      @
                      MyWidget::MyWidget()
                      {
                      c_pSortModel = new MySortModel(this);
                      c_pSortModel->setUserData(pDataSource);
                      c_pModel = new MyModel(pDataSource); //c_pModel: Inherited from QAbstractItemModel
                      c_pSortModel->setSourceModel(c_pModel);

                          c_pTreeView = new QTreeView(this);
                      
                          //Do some initializing on c_pTreeView and add it to this widgets layout
                      
                          c_pTreeView->setSortingEnabled(true);
                          c_pTreeView->setModel(c_pSortModel); //call c_pTreeView->setModel(c_pModel) to avoid Bug
                      

                      }
                      @

                      and that's how the new Item is inserted:

                      @
                      //In a slot connected to a changed-signal emitted by my DataSource-class:
                      if (pItem) //previously determined; everything works fine to this point
                      {
                      beginInsertRows(index, pItem->childrenCount(), pItem->childrenCount()); //in the error-case childrenCount() returns 0 (correct, new Item is first child), so the new Item should become item 0 (the first), so everything should be fine...
                      new MyTreeItem(pData, pItem); //pItem is set as parent, the tree-structure is set up correctly
                      endInsertRows();
                      //calling reset() afterwards would help, but I don't want to do that for performance reasons
                      }
                      @

                      So I hope I suceed in building a demo-project containing exact the same error, but as I already tried, I can't promise...
                      But perhaps the code I posted already helps...

                      1 Reply Last reply
                      0
                      • M Offline
                        M Offline
                        Mario84
                        wrote on last edited by
                        #11

                        I wasn't able to reproduce the error in a small demo-project...
                        but I found another workaround:
                        emit layoutAboutToBeChanged() before and emit layoutChanged() after inserting the row helps.
                        And seems to be better than inserting as Item 1, 1 as that caused an assertion in qsortfilterproxymodel.cpp in some cases. The layoutChanged-version does not (and doesn't give me the invalid rows debug message)...

                        1 Reply Last reply
                        0
                        • M Offline
                          M Offline
                          Mario84
                          wrote on last edited by
                          #12

                          If somebody is still interested in this:

                          The problem was the columnCount given by my model: QAbstractItemModel::columnCount() didn't return the same value for every index, and QTreeView doesn't seem to like that ;)
                          Now it always returns the same number and everything works fine.

                          1 Reply Last reply
                          0
                          • C Offline
                            C Offline
                            Christon
                            wrote on last edited by
                            #13

                            THANKS

                            Following line saved my second day on same issue!

                            "The problem was the columnCount given by my model"

                            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