Removing rows from QTreeWidget (qt programming) - qt

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.

Related

QTreeView values of parents / children changed in QModel

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.

QML TableView access model properties from delegate

I have a TableView for which I've defined my own itemDelegate. Now, from within this delegate I can access the value for the column using styleData.value, but I'd also need to access the other properties in this same item but I can't find how to.
I need this, because the text styling needs to change depending on some other property of the item model.
Any ideas? thanks!
There is some documentation missing. Within the item delegate you can access the following (taken from the source code of TreeView.qml):
styleData (see documentation)
model (currently not documented)
modelData (currently not documented, not sure about this but I guess it's similar to ListView)
(By the way, what's also missing in the documentation but which is useful is styleData.role. Also, the documentation of the other delegates lacks some available properties too; the best is to peek into the source code of the QML file and have a look for the Loader element which instantiates your delegate. As a plus you learn how that creepy stuff works. ;))
With model and the row/column information you can then navigate to the item data. This code depends on the type of model.
If you're using QML's ListModel, then you can use model.get: model.get(styleData.row)[styleData.role] should then work (untested since I use it rarely, please give feedback).
If you're using a C++ QAbstractItemModel or friends, the best is to add a slot to the model class which takes just the row and role name, since that's the information the TableView works with (nor with role numbers nor with columns...).
However in both cases you shouldn't use the expression in a property binding! The notification system will not work since you don't use the property system for accessing the data. According to your question, I guess you wanted to use it in a expression with binding. I don't know how to properly listen to changes in the model manually.
An alternative approach is to access the other items of the row and provide a property there. Some hints:
From within one item, you can access other items of the same row by walking the object tree up twice (first to the Loader which instantiates your component, then to the actual row) and then down twice (first to the particular child object which is a Loader, then its instantiated item). You need to know the column number you want to access (not the role name), I assume you want to access the first column (index 0):
parent.parent.children[0].item
You can provide the model data using a property in each item. Assuming a simple Text element this might be:
Text {
property variant value: styleData.value // <-- Here you make it available
// your other stuff
}
Putting them together could look like the following. In this example I assume the first row contains an integer, and if it is zero, the second column should be red.
// (within TableView)
itemDelegate: Text {
property variant value: styleData.value
text: styleData.value
color: (styleData.column == 1 && parent.parent.children[0].item.value === 0)
"red" : "black"
}
I think it's pretty easy if you read the source code of TableViewItemDelegateLoader.qml (it is a private code in qtquickcontrol)
To access any role you use use : model[your_role_name] .
For exp: model["comment"]
Faced with same problem today, this is result of my investigations (Qt 5.2.x)
If you have hard limit to TableView, there is only one correct solution - use model.get(styleData.row)["roleForStyling"] as #leemes wrote. But it will very slow if you have big amount of data in model and using, for example, proxy model for sorting/filtering.
Direct solution from #leemes answer is great, but in general case not be working, because in TableView any Item wrapped in Loader and therefore independent from parent and other items:
When some item is created (where you want to change text style)
another element (from which to receive identity) cannot yet be
created
You may not have "parent" on item creation (i.e. binding will
be broken)
In my case, the best solution for deep customise was creation of the simple wrapper for ListView. In this case you have access for complete row data in delegate without the overhead. Highlights for making component ("My own ListView as table"):
Create standalone header (Rectangle or Item) - do not use header form ListView.This make it fixed for any amount of data.
Wrap ListView to ScrollView (if you need scrollbars)
Use Clip: true property in list for make correct
Set style for highlight and set highlightFollowsCurrentItem:true in ListView
As bonus in future this may be used for make "TreeTable" :)

How to delete an item from model view?

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.

Deleting a row which has children in QTreeView

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).

exclude single items from grouping in groupingcollection

I have a flat data array that comes form a remoteobject, I want to group whatever is to be grouped, but leave single items (the ones with no common data with anything else) alone and without grouping, it's annoying to open each node only to find there's just one item inside, so there was no need to put it inside that group anyway.
Is this something anyone has done? I can't find any reference and I don't know if getting the hierarchicaldata out of the groupingcollection and then iterate thru it would be any good, sounds like a lot of duplicate work.
I ended up doing what shaunhusain said, I created my own copy of groupingcollection and monkeypatched the way it creates the groups, not clean enough for posting or general use yet, but working on it.
can also be accomplished by using a groupitemrenderer and hiding the disclosure icon based
on the number of children.
<mx:AdvancedDataGrid id="adg"
groupItemRenderer="my.namespace.GroupedItemRenderer"
</mx:AdvancedDataGrid>
GroupedItemRenderer is a subclass of AdvancedDataGridGroupItemRenderer
In updateDisplayList :
if (data && data.hasOwnProperty("children")) {
disclosureIcon.visible = (data.children.length > 0);
}

Resources