Solved QTableView item color to vary by value
-
Hi,
What about a proxy model like QIdentityProxyModel ?
-
@SGaist
You are a man of few words! :) I have read up aboutQIdentityProxyModel
. Let's see if I understand what you are suggesting.For example, a proxy model could be created to define the font used, or the background colour, or the tooltip etc. This removes the need to implement all data handling in the same class that creates the structure of the model, and can also be used to create re-usable components.
So, I think this could be used because I said I have a variety of model types. This would then allow me to put the logic for foreground color/role in one place, rather than in each of my 3 sub-classes of these. Is that what you had in mind?
However, that itself is not my problem. My question revolves around the fact that in order to decide what color I want I need to look at the value of each item. This is the case whether I implement via
data(ForegroundRole)
or viaQStyledItemDelegate
(which represent very different ways of approaching setting the color).So, for example, if I go down my (preferred) route of doing it by role instead of render delegate, whether or not I use a proxy model I will end with code for sub-classed
model.data()
which has to look like:def data(self, index: QtCore.QModelIndex, role: QtCore.Qt.ItemDataRole=QtCore.Qt.DisplayRole) -> typing.Any: if role == Qt.ForegroundRole: dataVal = super().data(index, Qt.EditRole): if isinstance(dataVal, float): if dataVal < 0.0: return QtGui.QColor(QtCore.Qt.red) ...
The point here is that when called for
data(index, ForegroundRole)
my code has to in turn calldata(index, EditRole)
to retrieve the data value in order to decide what to return for the color. I would still need to do same access to data value if I did my color viaQStyledItemDelegate::paint()
.That is what "worries" me. I don't know how "costly" that is, or whether there is any better way. If this is "fine" & "normal" for accessing the data value when deciding the color then please say so and I am good to go?
-
I would say that this is the normal way but likely not the most efficient.
One alternative would to store the foreground color when a value changes. It will cost memory in place of time spent to access each value when the role is requested.
-
@SGaist
Thank you for replying.I have implemented the
data()
approach and it works.I did consider overriding
setData()
to store the color against the value at assignment time. I rejected it for 2 reasons:-
When using
QSqlTableModel
, query result set population do not causesetData()
to be called. So colors would not get set initially. -
When using
QSqlQueryModel
, as above, plus as it's read-only, there is adata()
but not asetData()
.
Am I right about these? Did you mean that I could have written the code in slot for
QAbstractItemModel::dataChanged
signal instead of overridingsetData()
? -
-
dataChanged
is only a signal, but yes, you could connect it to a slot to update the foreground color if you keep it somewhere. -
@SGaist
Yes, I re-phrased. Last question, promise: would query/table models emit it as result set is read back in, whereassetData()
does not get called there? [Cannot test atm.] -
Sorry, I'm not sure I'm following that last question.
-
@SGaist
When result set is received from db via something likeQSqlQueryModel::setQuery()
rows/columns in model are populated. I believesetData()
is not called/involved. How would I recognise this (so as to populate colors for initial values received): will model emitdataChanged()
, or would I need to handlerowsAboutToBeInserted()
orbeginInsertRows()
ormodelReset()
or what? -
Since it's pretty heavy change, I would check for the modelReset signal in this case.
-
@SGaist
OK, it was really for interest, thanks for your time. In my case as I said I have implemented via calculated return result fromdata()
rather than setting the color by pre-storing it. It seems efficient enough for my purposes.