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

QTreeView not showing first child added to parent



  • I have a QTreeView on top of a custom module.
    I allow the user to add a child item for a selected item in the model.
    Every time a child item is added to its parent, I invoke the begin/end pairs of method as documented here: http://doc.qt.io/qt-5/qabstractitemmodel.html#beginInsertRows
    After that, I also work on the view to focus on the added item, in particular:

    • obtain a QPersistentModelIndex corresponding to the parent
    • insert the child row
    • view->expand() on the parent item (through persistent index) to show its children
    • view->update() on the parent item
    • select the lastly added child

    This works almost all the time, EXCEPT when I add the first child to a parent element with no children.
    The item is correctly added to the model, but the view doesn't show it.
    Forcing a full expand/update on the view shows the item, but it not a good solution as modify the collapse state of all the tree items.

    It there something else/different I should do?
    Thanks

    P.S. When adding the first child to a model item, beginInsertRows() is invoked using beginInsertRow (parentQIndex, 0, 0) - I believe this is the correct call to do



  • Difficult to reply with no code. Can you post what you are doing?



  • Here is an extract of the code which shows the issue I'm having when adding the first child to a parent element.
    Thank you

    // mView is a QTreeView
    // the model is a custom made model derived from QAbstractItemModel,
    // which adds the child elements correctly, see AddArrayEntry below
    
    // slot invoked when the  "add-child" button is pressed
    void AddChildSlot() 
    {
       // current selection from the view
       QModelIndex index = mView->selectionModel()->currentIndex();
       // helper class to implement the model
       PropertyTreeItem* item = static_cast<PropertyTreeItem*>(index.internalPointer());
    
       // selected element is the parent, add the new child at the end 
       if (/*parent item selected*/)
       {
          // save a persistent index corresponding to the array
          QPersistentModelIndex pmi(index);
    
          // see implementation below
          // the model adds the the item correctly
          mModel.AddArrayEntry(index);
    
          // does NOT work when adding the first child to the parent
          mView->expand(pmi);
          mView->update(pmi);
          // as a workaround I can use this, which messes up the view
          // mView->expandAll();
          // mView->update();
    
          // retrieve regular index from persistent one.
          QModelIndex normalIndex = pmi;
          // select added child
          mView->selectionModel()->setCurrentIndex(normalIndex.child(item->getNumChildren() - 1, 0), QItemSelectionModel::ClearAndSelect);
          mView->setFocus();
       }
    }
    
    
    void CustomModel::AddArrayEntry(const QModelIndex &index)
    {
       // grab internal pointer and prop
       PropertyTreeItem* item = static_cast<PropertyTreeItem*>(index.internalPointer());
    
       // get the internal array class
       <internal-array>* ap = item->AsArray();
    
       // compute index of the new row we're going to add
       int rowIndexToInsert = ap->Size();
    
       // notify row number about to change in the model
       beginInsertRows(index, rowIndexToInsert, rowIndexToInsert);
    
       // create a new element based on the prototype and the correspoding model tree item
       PropertyTreeItem* insertedItem = createTreeItem(/*params*/);
    
       // add the new item both on the internal array AND in the model wrapping it
       ap->Add(entry);
       item->addChild(insertedItem);
       
       // done inserting rows      
       endInsertRows();
    }
    


  • Hi, i read your problem description and your source code also , i hope that i can help you perfectly but i have something is ambiguous for me , and i need to understand them .

    • What do you mean by PropertyTreeItem class in your code , i think that a class dereaved from the abastractitemView or QStandarItem (did you mean the PropertyTreeItem * item the new item that you want to add ) ?
    • Just i wante to know how are you checked if the item is correctly added to the model (that my be wrong or is get the same result always ) ?

    I wante you to check befor this statement "PropertyTreeItem* item = static_cast<PropertyTreeItem*>(index.internalPointer());" if is doing the correct cast or no in the AddArrayEntry() method with debugging mode also rowIndexToInsert value when the item has no children .



  • Kind of guessing here but since you are not adding columns to the parent the view might just ignore the added rows. That would also explain why collapsing+expanding fixes it. try adding beginInsertColumns and endInsertColumns as well when the parent has no children



  • @VRonin said:

    Kind of guessing here but since you are not adding columns to the parent the view might just ignore the added rows. That would also explain why collapsing+expanding fixes it. try adding beginInsertColumns and endInsertColumns as well when the parent has no children

    Thanks @VRonin, I've tried your solution but still does not cover 100% of the cases.
    On the same line I've also tried mView->update() not only on the parent item, but also explicitly on all of its children: still working only sometimes, not always...

    @Maarouf-Med-Mahdi PropertyTreeItem is the internal used to build the model on, see: http://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html
    I'm sure the model is updated correctly because I've debugged it, and if I jump on another item and than relesect the one I've modified, the added child is shown correctly, which means that it's a problem of refreshing the view, not about the child item not added to the model.



  • @rickyviking
    There seem to be a few questions about this type of behaviour.

    From one of them (https://forum.qt.io/topic/18024/solved-qtreeview-child-indicator-is-not-updated-after-inserting-children):

    • Are you using any kind of sort behaviour (inc. proxy) on the model/view?

    • Are your columnCount()s returning the same number on every single index in the view (possibly including the parent)?



  • @rickyviking said in QTreeView not showing first child added to parent:

    I'm sure the model is updated correctly because I've debugged it

    When it comes to subclassing models you can never be sure, believe me.

    @JonB 's points are 100% worth exploring but I'd also recommend running the model test alongside your program to make sure everything is implemented correctly



  • Thanks @VRonin and @JonB for your suggestions.

    I finally found the cause of my issue: the model I shared in the code snippet above is based on 2 columns.
    Sometimes the method to add a new child row was invoked with an index referring to the right row, but to column 1 instead of 0, because the user might have selected that cell as last one.
    This probably doesn't play well with begin/endInsertRows().
    I have now checked that the column index for which I call begin/endInsertRows() is always 0, and after this change the view always updates correctly.

    I confirm the model behaves correctly, but the model test is a nice tool anyway.



  • @rickyviking said in QTreeView not showing first child added to parent:

    This probably doesn't play well with begin/endInsertRows().

    It does play well, however None of the views provided by Qt handle children of items in columns that are not the first one


Log in to reply