PDA

View Full Version : Display different values in model versus proxy with a delegate



mclark
1st November 2010, 20:10
Qt 4.6.2 Commercial
Windows XP SP3

I have a QStandardItemModel (model) and a QSortFilterProxyModel (proxy). The proxy has delegates assigned to certain columns to handle some values specially because the proxy is to display some values differently than the model. (For an enumeration, the model holds an index value while the proxy is to display what the index references.)

I have QTableViews that display the values of both the model and the proxy. This works for one type of data I'm using (QByteArray->QString) but not another (int->enumeration string). If I do not assign my enumeration delegate, the values of both the model and proxy are the index. But, when assigning my delegate, the delegate paint() function is not called until the cell in question is displayed, and yet the value in the model is the enumeration string instead of the index.

I have a little experience with delegates but this behavior is very confusing. Can someone explain how the Qt:: DisplayRole value is getting changed in the model without the proxy delegate paint() function being called?

ChrisW67
1st November 2010, 22:52
I have a little experience with delegates but this behavior is very confusing. Can someone explain how the Qt:: DisplayRole value is getting changed in the model without the proxy delegate paint() function being called?
I am afraid that you will have to tell us because it is your code.

The Qt::DisplayRole of the standard models reflects a default conversion from the QVariant value you get on the Qt::EditRole. If there is an implicit QString conversion from whatever you are putting on the data then that is probably what you will get in the Qt::DisplayRole. In custom models you get complete control over what each role returns to the model consumers.

View delegates have nothing to do with the data returned by models. Delegates are attached to a view and called when a view needs to display an item. The QStyledItemDelegate::paint() method should render the value returned from the model using whatever visual is appropriate. The delegate can do some rudimentary changes to what it displays using the QStyledItemDelegate::displayText() method, but this does not alter the model or the data seen anywhere else.

mclark
1st November 2010, 23:13
I am afraid that you will have to tell us because it is your code.
I have no doubt that the problem is with my code. If I can better understand the magical workings of delegates and models, then I can fix it.

I'm considering placing a 'monitoring' delegate on the column of the model (basically with pass-through functions that I can put a breakpoint on) to see what is causing the change from index value to string value when assigning the delegate to the proxy. Does this sound like a reasonable approach or is there something more useful you might recommend for debugging this problem?

ChrisW67
2nd November 2010, 01:46
I'm not sure that you are using the term "delegate" in the sense it is normally used in Qt. A delegate in Qt is a helper for a view to extend the display options for data in the view. You don't assign delegates to models or proxies, you attach them to views e.g. QAbstractItemView::setItemDelegate().

You can either derive from QStandardItemModel and override the data() method to provide an inspection point or you can overlay a proxy model that provides a monitorable data() method. I'd probably opt for the first unless you already have a custom proxy model. However, the QStandardItem is just going to regurgitate exactly what you put into it when you created it.

mclark
2nd November 2010, 14:51
You don't assign delegates to models or proxies, you attach them to views
Yes, I was using poor terminolgy.

I have 2 views of the same data. One view shows raw data unfiltered by a proxy and using the default delegates. The other view is filtered by a proxy and has a custom delegate attached to the problematic column.

The source (unfiltered) view is filled prior to the proxy view being instantiated, the data at that point is correct. The value of the table cell in question, in the unfiltered view, changes when I attach the custom delegate to that column of the proxy view. I understand that somehow my code is the cause of this change. I need to find out how/why that is occuring. I'm looking for a way to debug this.

Since my delegate is attached to the view using the proxy I assumed that it was causing the data change in the source view. I shall start monitoring the itemChanged() signal of the source model to try to determine when/how this is happening.

Thanks for your help.

ChrisW67
2nd November 2010, 21:43
The two views are independent of each other. Attaching a delegate to one cannot affect the other unless you are doing something inside the delegate that works outside the model/view framework and has side effects on the original model. The delegate should, for example, never call setData() on the model.

mclark
3rd November 2010, 14:58
The two views are independent of each other.
You are correct! I found a place in my code where I was setting a value in the model instead of the proxy. Thanks for your support!

I am required to make certain proxy cells read-only (disabled) but can only see a way to apply that to the model with a setFlags() call. This is not a big deal since the user will never actually see the model, only the proxy. But for completeness I would like to restrict my modifications to only the proxy.

Do you know of a way to disable a proxy model table cell? I suspect it may be able to be done via the delegate paint() call but I don't know how.

ChrisW67
3rd November 2010, 23:18
It really depends on the reason for a cell to read-only. If it is based on the value of certain data in the model (even other indexes) then you can modify the model (or proxy) flags() method to look at the related data and return the correct flags when requested - this has no connection to the delegate. For example, if column 1 is editable only if the value in column 0 is True then when flags() is called for a cell in column 1 it should look at the corresponding column 0 cell value and either return editable or not-editable flags.