I am using QTreeView and QAbstractItemModel to establish view whose data also comes from a tree structure. But when I delete a node from a tree structure(data source), then I found that the model view can't automatically adjust itself, it also use the invalid pointer which I don't know it points to which memory block. I don't know how to refresh or what I need to do to fix this problem.
To delete data from the model, use beginRemoveRows() and endRemoveRows().
beginRemoveRows tells the model that you will now change the underlying data structure.
Then change the structure and call endRemoveRows when done. endRemoveRows will then trigger the notifications to update the views:
beginRemoveRows(QModelIndex(), 0, 0);
m_topLevelNodes.remove(0);
endRemoveRows();
This removes the first top-level row (and its children), assuming that the underlying structure in your model keeps the top-level tree items in a container named m_topLevelNodes.
Related
I have a hierarchical datastructure which I wrapped in a QModel (inherited from QAbstractItemModel) and which I show and edit in a QTreeView.
Let's assume that QTreeView shows the following data:
Item1
|----Item2
|----Item3
|-----Item4
|----Item5
Now the following shall happen:
1) I edit Item3 and change it's value to Item3_a.
2) The QModel recognizes the change and changes the items' values of parents and children in the wrapped model to:
Item1_a
|----Item2_a
|----Item3_a
|-----Item4_a
|----Item5_a
3) The QTreeView gets informed by the model about the additional changes (Item1,2,4 and 5). Only the displayed values are changed. The hierarchical structure remains the same.
My questions aims on step 3:
How do I notify the QTreeView about the changed data properly?
This is what I tried:
I know that there is modelReset, but then the QTreeView gets collapsed. However it should keep its collpase/expanded state.
According to the docs using models setData method with different parent indices gives undefined behaviour. I tried calling setData recursivly from setData for each parent/child, but this leads to program crash.
I'm using qt5.
Pretty sure that what you're looking for is "rowsInserted" and the methods that relate to it. The "dataChanged" signal indicates that a given cell (or range) has changed values; it's not about changing table structure.
What you're doing here is removing and inserting rows as you move entries from one parent to another. You need to implement all of the methods related to that. There's also a "rowsMoved" that may better suit your needs.
I have finally implemented my own tree model (inherited from QAbstractItemModel) for a QTreeView.
A blueprint of what I did can be found here:
http://www.trinitydesktop.org/docs/qt4/itemviews-simpletreemodel.html
So, I have:
the user-defined tree items, which are pure C++ (no Qt) and these are wrapped by
the TreeModel class which is inherited from QAbstractItemModel (like in the example link above).
I now have a generated tree hierarchy of tree items from (1.). This hierarchy has thousands of items, and I want to insert this hierarchy into my existing model at runtime.
How do I do that?
(All I have is the root-node to the c++ tree hierarchy as TreeItem pointer and a QModelIndex of the existing model where the "new sub-tree" has to be inserted)
I found modelAboutToBeReset(), modelReset(), and endResetModel() from here: http://qt-project.org/doc/qt-4.8/qabstractitemmodel.html#beginResetModel
But I don't know if these are the right functions, and, if they are, how to use them.
Any ideas?
You should call modelAboutToBeReset() before removing real items from your model. This call will "freeze" all views from requesting any data. After removing all real items you should call endResetModel() - it will unfreeze data requesting and force all connected views to update it content.
This is what i did:
void
TreeModel::addNewSubTreeToModel( TreeNode* t_rootOfNewTree, TreeNode* t_addNewSubTreeAsChildOfThisItem )
{
beginResetModel();
t_rootOfNewTree->setParent(t_addNewSubTreeAsChildOfThisItem);
t_addNewSubTreeAsChildOfThisItem->addChild(t_rootOfNewTree);
endResetModel();
}
I am new to Qt.
I have the following situation.
Can someone suggest me how to tackle it.Thanks
I have a custom made model which i should populate in the backend.ie when the program starts there is no guarantee there will be elements in the model.But these elements may be added later in the backend.So if i add a new element in the data structure in the model how do i let the view know the change.And this is an insertion and not a change in the data.
Also if i want the view i display to be sorted how should i notify the view
To update any connected views of an insertion, call beginInsertRows(const QModelIndex& parent, int first, int last) before you modify the model, and endInsertRows() after. Read the docs.
To sort views you need to use a QAbstractProxyModel, it is highly configurable so read the docs before asking more specific questions about it.
I want to delete a row which has children from a QTreeView. I use QAbstractItemModel's removeRow ( int row, const QModelIndex & parent = QModelIndex() ) method,pass the row and parent index of the deleted row. But this method returns false.
How can I delete a row which has children? Do I need write a method to recursively delete rows?
You should look at this: removeRow
This is a convenience function that calls removeRows(). The QAbstractItemModel implementation of removeRows() does nothing.
And here in QAbstractItemModel::removeRows():
The base class implementation does nothing and returns false.
If you implement your own model, you can reimplement this function if you want to support removing. Alternatively, you can provide your own API for altering the data.
I know I'm a bit late to the party, but I wanted to document this because I can't seem to find any good answer to the original question.
You need to implement QAbstractItemModel::removeRows in your model. There is a Qt example, Editable Tree Model, that shows how this should be done. The basic procedure is to call beginRemoveRows, delete the item(s), then call endRemoveRows.
Your tree item class should have a method for deleting a range of its child items. You call this method on the parent item from within your reimplementation of removeRows. The tree item class should be set up to delete its children when it is destroyed. The Qt example does this through the destructor, though with C++11 and later this is best done by storing children in a container of smart pointers so they get automatically deleted when the container goes out of scope.
You do not need to account for child items being collapsed or expanded in the tree view - QTreeView knows whether or not child items are visible or not and will update the view accordingly. In other words, if you delete a tree item with a few child items that were visible in the tree view, they will be automatically removed from the view. This is something that I can't find documented anywhere, but from personal experience I can say that it works (as long as you call beginRemoveRows and endRemoveRows correctly).
what's the best way to remove a row (QTreeWidgetItem) from a QTreeWidget?
The QTreeWidget content has been set by:
myQTreeWidget->insertTopLevelItems(0, items); // items = QList<QTreeWidgetItem*>
then I remove an item from my QList "items" and I try to clear/reset the QTreeWidget
packList->clear();
packList->insertTopLevelItems(0, items);
but my app crashes here!
Suggestions?
Your problem is that calling packList->clear() deletes the tree widget items contained by the tree. (See the documentation about QTreeWidget::clear(), which includes a note about the items being removed from the tree before deleting.) You'll either need to find a way to remove the items, or not maintain a list of them separately from the tree.
On a slightly-related note, if you are trying to keep track of other data along with the tree, I'd recommend you try to use the models paradigm. In non-trivial cases, it has usually been worth my while to convert to that technique, rather than using the widgets/items.
From what this documentation says, you should be able to do it with:
packList->takeTopLevelItem(index);
Which returns removes and returns the item at the supplied index.