PDA

View Full Version : Using Qt::UserRole in the Model/View architecture



d_stranz
21st January 2011, 20:04
Can someone point me to an example / tutorial / explanation of how to correctly use Qt::UserRole in the Model / View architecture?

If I set user role data into my model items, how or when will the model's data() method be called with a role value corresponding to my user role?

Does the act of calling setData() with a role >= Qt::UserRole result in an entry being made in a dispatch table somewhere in the model that tells it to add this role to the list of other roles that are called via the data() method?

If not, then in general how or where should user role data be retrieved by an application that uses it?

I've read the Qt documentation and tutorials covering the model / view architecture and classes, and while there are frequent references to the concept that "user roles can be used for application-specific purposes", I can't find anything that tells how such roles are actually integrated into the architecture.

Thanks in advance for any information.

ecanela
21st January 2011, 20:41
check the page http://www.ics.com/learning/icsnetwork/ search the model-view

need suscribe, but the video are ilustrative and clear.

d_stranz
21st January 2011, 22:33
check the page http://www.ics.com/learning/icsnetwork/ search the model-view

need suscribe, but the video are ilustrative and clear.

Thanks. I had downloaded and saved the Model-View video a long time ago, and I just watched part of it again. In it, Johan Thelin mentions user roles and says they can be used with custom delegates, but still doesn't explain how.

So, looking through more Qt documentation, it seems that custom delegates are the only way that user roles can be used, through the QAbstractItemDelegate methods that take a QModelIndex reference as argument. (Through the QModelIndex::data() method, called with Qt::UserRole).

Is that correct?

wysota
21st January 2011, 22:36
If I set user role data into my model items, how or when will the model's data() method be called with a role value corresponding to my user role?
Automatically - never. Qt::UserRole up to Qt::MaxUserRole are identifiers you can use for your own custom data fragments.


Does the act of calling setData() with a role >= Qt::UserRole result in an entry being made in a dispatch table somewhere in the model that tells it to add this role to the list of other roles that are called via the data() method?
No, you can always call data() with any possible integer as the role identifier. It is strictly up to the model to handle the situation - if it knows anything about custom roles, it will use them, otherwise it will return an invalid QVariant().


I've read the Qt documentation and tutorials covering the model / view architecture and classes, and while there are frequent references to the concept that "user roles can be used for application-specific purposes", I can't find anything that tells how such roles are actually integrated into the architecture.
The default models, views and delegates don't handle user roles. But it doesn't mean they don't implement custom roles at all. For instance QDirModel and QFileSystemModel are able to handle the FilePathRole which is a custom role. The same way you can define custom roles for your models if you need them.

d_stranz
21st January 2011, 23:13
Thanks. I think I basically understand this now. I was hoping I might be able to use user roles as an automatic part of the framework but apparently I can't.

My implementation problem is this: I have implemented a custom QTableView that contains QwtPlot instances in the cells of two columns. The solution I implemented was to implement a slot for the model's modelReset() signal. In this slot, I create the QwtPlot and use setIndexWidget() to put them into the view. This seems to me to be a kludgy way to do this, but it works.

I had tried using a custom delegate to wrap the QwtPlot instance, but I couldn't find an appropriate place to create the QwtPlot instance. The createEditor() method isn't it, because the cell isn't editable, and my understanding is that the same delegate instance could be used for the entire view (if calling QAbstractitemView::setItemDelegate()), so I can't create the widget in the delegate constructor.

So, is there a better (i.e. more elegant) way to accomplish what I'd like to do using user roles and/or delegates that doesn't involve this out-of-band kludge?

I've attached a screenshot of this table.

5807

wysota
22nd January 2011, 08:45
if you use setIndexWidget then the widget you set has no relation to the model-view architecture -- it is just a standalone widget positioned somewhere in the view widget.

if you want to display a plot in a view then a better solution is to implement a custom delegate that will (in its paint routine) use QwtPlot::print or something similar to render a plot in the item without explicitly showing any widgets.

d_stranz
23rd January 2011, 00:45
if you use setIndexWidget then the widget you set has no relation to the model-view architecture -- it is just a standalone widget positioned somewhere in the view widget.

Right. That's why I consider it a kludge.


if you want to display a plot in a view then a better solution is to implement a custom delegate that will (in its paint routine) use QwtPlot::print or something similar to render a plot in the item without explicitly showing any widgets.

That would be very "heavy", since I would have to temporarily instantiate a QwtPlot, configure it (which is where the user role data would come in), render it, then delete it, on every paint event on every delegate that contained a plot. I understand that using a custom delegate would be the correct way to do it within the M-V architecture.

I'll think about that for the next time I need to do something like this. The current project is too close to release to do so much experimentation.

wysota
23rd January 2011, 11:24
That would be very "heavy", since I would have to temporarily instantiate a QwtPlot, configure it (which is where the user role data would come in), render it, then delete it, on every paint event on every delegate that contained a plot. I understand that using a custom delegate would be the correct way to do it within the M-V architecture.
I don't know Qwt very much unfortunately but maybe there is a class that allows you to build a plot that is not a widget, then it should be somewhat lighter. On the other hand if you use setIndexWidget then you end up with a similar architecture anyway, the difference is whether it is tied to the model-view arch. or not. And the overall performance also depends on which solution you choose.

d_stranz
23rd January 2011, 16:13
I don't know Qwt very much unfortunately but maybe there is a class that allows you to build a plot that is not a widget, then it should be somewhat lighter. On the other hand if you use setIndexWidget then you end up with a similar architecture anyway, the difference is whether it is tied to the model-view arch. or not. And the overall performance also depends on which solution you choose.

As I think about this more, the idea of a QwtPlot widget inside a delegate might be feasible. The delegate -can- instantiate a single QwtPlot on construction and use that for all cells. That makes it much lighter weight than my current solution of a widget per cell.

My users do need to be able to edit by interaction with certain items contained in the plot, the the delegate can handle that by using it's QwtPlot instance as the editor. For normal painting, I can render the widget contents to an image and simply display that in the cell. I should be able to create that image and attach it to the model as user role data. (I'll ignore the fact that models can be shared among views for now). When the view resizes, I will need to recalculate and cache all of the visible images, but I need to do that now with the widgets anyway.

Thanks for all this useful discussion. It has allowed me time to think about the problem and use your answers to guide me to a better solution.