2

I've been working really hard trying to find a solution to this for the past few weeks. I have committed to a direction now, but I am still not entirely satisfied with what I have come up with. Asking this now purely out of curiosity and for hope of a more proper solution for next time.

How on earth do I keep multiple QAbstractItemModel classes in sync that are referring to the same source data but displaying in different ways in the tree view?

One of the main reasons for using model/view is to keep multiple views in sync with one another. However, if each of my views requires different data being displayed at the same column, as far as I can tell I need to then subclass my model to two different models with different implementations that will then cater to each of those unique view displays of the same items.

Underlying source items are the same, but data displayed is different. Maybe the flags are different as well, so that the user can only select top level items in one view and then can only select child items in the other view.

I'll try to give an example:

Lets say my TreeItem has three properties: a, b, c.

I have two tree views: TreeView1, TreeView2. Each has two columns.

TreeView1 displays data as follows: column1 -> a, column2 -> b

TreeView2 displays data as follows: column1 -> a, column2 -> c

I then need to create two different models, one for TreeView1 and one for TreeView2, and override the data and flags methods appropriately for each.

Since they are now different models, even though they are both referring to the same TreeItem in the background, they are no longer staying in sync. I have to manually call the refresh on TreeView2 whenever I change data on TreeView1, and vice versa.

Consider that column1, or property a, is editable and allows the user to set the name of the TreeItem. Desired behaviour would be for the edit that is done in TreeView1 to instantly be reflected in TreeView2.

I feel like I am missing some important design pattern or something when approaching this. Can anyone out there see where I am going wrong and correct me? Or is this a correct interpretation?

Thanks!

Mathieson
  • 1,194
  • 2
  • 13
  • 28

1 Answers1

2

One way to do it is to use viewmodels. Have one QAbstractItemModel adapter to your underlying data model. All interaction must pass through that model. When you need to further adapt the data to a view, simply use a proxy view model class that refers to the adapter above and reformats/adapts the data for a view. All the view models will then be automagically synchronized. They can derive from QAbstractProxyModel, although that's not strictly necessary.

There is no other way of doing it if the underlying source of data doesn't provide change notification both for the contents and for the structure. If the underlying data source provides relevant notifications, it might as well be a QAbstractItemModel to begin with :)

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • Interesting. I have been planning on doing something along those lines (using QSortFilterProxyModel) although only to filter out certain items depending on the view. I would have still been duplicating the underlying models though. Sounds like I should research the proxy models further to get a better understanding of them. – Mathieson Mar 18 '15 at 21:33
  • @Mathieson A proxy model is very nearly a view that doesn't have a gui, but a model API in place of a gui. Think of a proxy as if it was a machine-readable view, where it was agreed that the machine-readable API is that of a model as well. – Kuba hasn't forgotten Monica Mar 18 '15 at 22:08
  • Do you have any good resources you can link to on accomplishing this or some examples of good implementations? This is the best I have found so far on the subject http://imaginativethinking.ca/use-qt-qsortfilterproxymodel/ – Mathieson Mar 18 '15 at 22:53
  • A remaining question, even after this article I linked, is how to configure properly for TreeViews. His examples seem to be applicable to list views. My model hierarchy has multiple levels to it. In some of my views, I need to display data which in the main model is, say, a 3rd level child. Simply filtering tree items based on type would hide the parent items, which would in turn hide the child item. Is the key in overriding the mapFromSource methods in some way so that 3rd level children are remapped to top level? – Mathieson Mar 18 '15 at 23:04
  • Just found this page that has a good example (which you actually provided!) http://stackoverflow.com/questions/21564976/how-to-create-a-proxy-model-that-would-flatten-nodes-of-a-qabstractitemmodel-int – Mathieson Mar 19 '15 at 04:18