views:

135

answers:

1

I am working on a mapping application and need to display the data objects using a table, a form and as graphical objects in the map. I'm using PyQt, but that's not really important as this is a Qt question not a Python question.

If I only needed the table and form views this would be easy, I'd just use the Qt Model/View framework. However I need the map view to provide functionality only really available using the Graphics View framework, which is essentially it's own Model/View framework with the QGraphicsScene acting as the data model.

I can think of two ways to do this. One would be to start with an authoritative model subclassed from QAbstractItemModel, link it to a subclass of QAbstractItemView and from there generate and update QGraphicsItems in the scene. This looks ugly though because I'm not sure how to handle user interaction with and changes to the data items though interaction with the QGraphicsItems.

The other way I can think to do it is to treat the QGraphicsScene as the authoritative data source, storing the data object in each QGraphicsItem's .data() property. I'd then subclass QAbstractItemModel and write it so that it accesses the data in the scene as it's data store, the other views would then use this as their model. How would I propagate changes to the data in the scene up to the model though?

Whichever approach I take, it looks like there's a gap not handled by the frameworks. In Model/View all changes are assumed to be made in the model. In Graphics View all changes are assumed to be made in the scene.

So which approach would you choose QAbstractItemModel(authoritative)->QAbstractItemView->QGraphicsScene or alternatively QGraphicsScene(authoritative)->QAbstractItemModel->Other Views. Why would you choose one over the other and what gotchas do you anticipate? Has anyone else needed to bridge this gap between Qt's twin model/view frameworks and how did you do it?

+3  A: 

QAbstractItemModel(authoritative)->QAbstractItemView->QGraphicsScene

Without a doubt. I have done this before, it does require a bit of duplication (at least some that I couldn't avoid) but nothing too bad.

This also allows you to represent your data in standard views along with the scene which is quite nice.

My best advice would be to store a QHash of QPersistantModelIndex to QGraphicsItem and a QGraphicsScene in the QAbstractItemView you create. This allows you to quickly go between Model/View land (QModelIndex) to Graphics View land (QGraphicsItem)

Adam W
This is the approach I have started with, before I realised I could do it the other way around. I'm guessing the only methods of AQbstractItemView I'd need to subclass are dataChanged(), rowsInserted() and rowsAboutToBeRemoved()? Then manage the items in the scene appropriately. I expect I'll store QPersistentModelIndexes in the QGraphicsItems.I like the QHash idea. I'm using PyQT so I'd use a Python dictionary, but it's a nice optimisation either way.
Simon Hibbs
@Simon: Yep I think you got it, in dataChanged() you may have to duplicate some of the code from the QGraphicsScene depending on your data and representation, but again, it should be minor if any.
Adam W
Got it working, at a basic level. Yay!
Simon Hibbs
@Simon: Congratulations, hopefully the developments with QtQuick/QML and the like will make this even easier in the future.
Adam W
Also, Itemviews NG (http://labs.trolltech.com/blogs/category/itemviews) should help in this area too, if they ever make it out of labs.
Casey