2
votes

I have a model that retrieves data from a table in a database from a certain SQL query, and shows the items in a QTreeView. The characteristics are:

  • the data comes from a table, but has an underlying tree structure (some rows are parents that have rows below them as children)
  • this tree structure is shown in the QTreeView
  • the children are selectable in the QTreeView (not so the parents)
  • the table in the database gets updated continuously
  • in the updates, a children can be added to any existing parent
  • periodically (with a QTimer) the QTreeView is updated with the contents of the table

Since the children are added at any time to any parent, the first silly approach when updating the QTreeView is clearing it all, and append all the rows again, in form of parent or children, to the QTreeView. This is a 0-order approximation, and it is indeed terrible inefficient. In particular, the following problems appear:

  1. Any existing selection is gone
  2. Any expanded parent showing its children is collapsed (unless ExpandAll is active)
  3. The view is reset to show the very first row.

What is the best solution to this problem? I mean, the first solution I will try will be not to clear the QTreeView, but instead parse all the returned rows from the table, and check for each of them whether the corresponding item in the QTreeView exists, and add it if not. But I wonder if there is a trickiest solution to engage a given table in a database with a QTreeView (I know this exists for a QTableView, but then the tree structure is gone).

2
Do you know which node should be updated? In other words, do you have an information on each particular item you should add to your tree?vahancho
The very first column retrieved (and not shown in the QTreeView) contains an index value which should tell me whether this item is a parent or children, and looking at the current QTreeView I should see if this is already in the view or not.J C Gonzalez
I believe, that if you properly insert your new items using beginInsertRows and endInsertRows, the tree view selection and nodes state will be preserved as it was before updating the tree.vahancho
OK, I will try and let you know, thanks!J C Gonzalez
Finally, after a careful analysis of what data is retrieved from the database, asking only for the records not previously obtained, and by using a couple of internal IDs for grouping the data and for sorting them, AND also a careful usage of beginInsertRows() and endInsertRows(), the current position and selection in the QTreeView receiving the model updates are preserved, and the items in the view are added and the view updated transparently for the user. BTW, in my case it was also important to re-apply the sorting status after each update. Thanks to all!J C Gonzalez

2 Answers

1
votes

This thread mentions a general approach, but this might get tricky quickly, but I am not sure how this would work if the underlying model is changing constantly (i.e. the QModelIndex becoming invalid).

Worst case is that you will have to write your own mechanism to remember the selection before updating and then re-applying it.

I assume you use some model/view implementation? You could enhance your model with a safe selection handling, in case the example mentioned above does not work for you.

1
votes

I guess this is the case for a self-answer.

As I presumed, after a careful analysis of what data is retrieved from the database, I had to do the following "upgrades" to the retrieval code:

  • I retrieve, along with the fields I want to show in the view, two identifiers, one for grouping rows and one for sorting items into groups
  • I also retrieve the internal record ID (an increasing integer number) from the table in the database, in order to ask only for new records in the next retrieval.

In the model population code, I added the following:

  • I first scan the initial records that may belong to existing groups in the model
  • When, in the scanning, I reach the last group in the model, this implies that the rest of retrieved records belong to new groups (remember the records are retrieved sorted such that items that belong to the same group are retrieved together)
  • Then start creating groups and adding items to each group, until we use all the records retrieved.

Finally, it is very important:

  • the use beginInsertRows() and endInsertRows() before and after inserting new items in the model
  • capture the sorting status of the view (with sortIndicatorSection() and sortIndicatorOrder()) and re-apply this sorting status after updating the model (with sortByColumn())

Doing that the current position and selection in the QTreeView receiving the model updates are preserved, and the items in the view are added and the view updated transparently for the user.