Solved 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?
ThanksP.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
andendInsertColumns
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
andendInsertColumns
as well when the parent has no childrenThanks @VRonin, I've tried your solution but still does not cover 100% of the cases.
On the same line I've also triedmView->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