QItemDelegate: colour all text in cells of a row
-
I am an amateur programmer learning to use PyQt5. I am currently coding an application to store and analyse physical training activity.
One of my forms prints out a QTableView listing previous years results with the last cell indicating a percentage which compares this season with previous seasons. When the previous season's total is surpassed an "Ok" was added to the percentage displayed
Image:

"Ok" was added because I didn't know how to colour the text to indicate that the target was surpassed.
Since then I have learned about QItemDelegate and have successfully coloured the "%" column but can't seem to code the other cells in the same row. Using the sibling() method I can get the text from the two previous cells but can't find a way of getting the option.rect data need to paint the text red.
Code to date:class MyDelegate(QItemDelegate): def __init__(self, parent=None, *args): QItemDelegate.__init__(self, parent, *args) def paint(self, painter, option, index): painter.save() # set text color painter.setPen(QPen(Qt.black)) text = index.data(Qt.DisplayRole) #index1 = index.sibling(index.row(), 1) #text1 = index1.data(Qt.DisplayRole) if 'Ok' in text: painter.setPen(QPen(Qt.red)) painter.drawText(option.rect, Qt.AlignCenter, text) painter.restore()Any help will be appreciated.
-
maybe try something like this which removes the need for Ok
def paint(self, painter, option, index): if siblingAtColumn(INDEX_OF_%_COLUMN).data() > 100: # red text if surpassed painter.save() painter.setPen(QPen(Qt.red)) painter.drawText(option.rect, Qt.AlignCenter, text) painter.restore() else: # default black text if not surpassed super().paint(painter, option, index) -
Thanks for the input.
I tried the code but as written "if siblingAtColumn(INDEX_OF_%_COLUMN).data() > 100"
siblingAtColumn is not identified. I changed the the code line to :if index.siblingAtColumn(INDEX_OF_%_COLUMN).data() > 100:but I get an error:
Unhandled AttributeError "'QModelIndex' object has no attribute ' siblingAtColumn'"This error I don't understand because QModelIndex does have siblingAtColumn function.
I don't understand the parameter "INDEX_OF_%_COLUMN". How is it initialize?
-
I didn't write the code properly I was just trying to give you the general idea of what to try. by INDEX_OF_%_COLUMN , i was referring to whatever your model's section value is for the '- % -' column which is the 3rd column in the table, judging from just the table I would assume it to be = 2.
so something like :# where column 2 refers to the column that determines if your target is surpassed. if index.siblingAtColumn(2).data() > 100: # OR row = index.row() if index.sibling(row, 2).data(Qt.DisplayRole) > 100or maybe you're on an earlier version since they were implemented after 5.11?
Another way to do it would be to directly access your model's data in the following way:
def paint(self, painter, option, index): row = index.row() model = index.model() # Incase you don't have access to your model surpassed_column_data = model.data(model.index(row, 2), Qt.DisplayRole) # might have to cast this as a float if you're displaying as string and strip the % sign col3 = float(surpassed_column_data.strip('%')) if col3 > 100: # red text if surpassed painter.save() painter.setPen(QPen(Qt.red)) painter.drawText(option.rect, Qt.AlignCenter, text) painter.restore() else: # default black text if not surpassed super().paint(painter, option, index) -
Thanks Erudite Monkey for the input,
I tried to convert the original code you proposed to python string using QString because of the error:
col3 = float(surpassed_column_data.strip('%')) AttributeError: 'QVariant' object has no attribute 'strip'The code I tried received an error QVariant' object has no attribute 'toString'.
Printing the QVariant.Type came back as a QString type
surpassed_column_data.canConvert(QMetaType.QString)came back as True.
I am new at PyQt and a little stumped as to why.
my current versions are:
Qt version: 5.9.5
SIP version: 4.19.7
PyQt version: 5.10.1Do I need to upgrade my Qt version to 5.13 to solve the problem.
In your first post you mentioned Pyside2. I made a quick research and found out that pyside2 is also called Qt for Python. I originally thought that this forum (Qt for Python) was for PyQt.
Further information: My operating system is Mint cinnamon 19.1. I went to the mint Forum to question on how best to upgrade Qt to 5.13
A couple of users informed me that mint requires Qt 5.9 to operate software correctly and that an upgrade could cause execution problems on my system.
I have also remembered that I recently upgraded PyQt to version 5.10. I am wondering if my string conversion problems are related ???
-
You should be working with virtual environments so no package installations interfere with your system. some common ones for python are :
- pipenv ... also pipenv
- conda: which comes with a much larger distribution called Anaconda with lots of scientific/ data science python libs.
- virtualenv / pipenv
with virtual environment managers like pipenv, updating pyqt is as simple as just typing :
pipenv update pyqt or pipenv update pyside2I'm not familiar with mint so I can't really say much about that. But it looks like your PyQt version 5.10 doesn't have sibling methods etc. I am using pyside2 with conda since I work with math stuff a lot, I would suggest you to look into pipenv for environment management since anaconda seems unnecessary. I would suggest to install pyqt or pyside2 in a virtual environment along with all the rest of your packages for this project with pipenv. If that seems too much of a hassle then try to work with virtual environments for future projects and for now you can just cast it as a string first manually:
col3 = str(surpassed_column_data).strip("%") col3 = float(col3) -
I will try a virtual environment. In the past I have come across many references to it. Never go around to trying it. I guess the time is now. I've also installed PySide2 started the process of learning the differences which pyside which I had tried years ago.
-
I will try a virtual environment. In the past I have come across many references to it. Never go around to trying it. I guess the time is now. I've also installed PySide2 started the process of learning the differences which pyside which I had tried years ago.
Erudite Monkey
Your code suggestion worked with a minor modification. Before I post the code I must say that I downloaded and installed PySide2 and started to work with it. It has all the advantages of PyQt without the translation code to python. Python strings are python strings not QStrings.
I took your first code suggestion of six days ago and removed from my code both the ' % ' and
' ok '.I added the line from my code to yours:
text = index.data(Qt.DisplayRole)The final code is:
class MyDelegate(QItemDelegate): def __init__(self, parent=None, *args): QItemDelegate.__init__(self, parent, *args) def paint(self, painter, option, index): text = index.data(Qt.DisplayRole) if float(index.siblingAtColumn(2).data().strip('%')) > 100: # red text if surpassed painter.save() painter.setPen(QPen(Qt.red)) painter.drawText(option.rect, Qt.AlignCenter, text) painter.restore() else: # default black text if not surpassed super().paint(painter, option, index)The image

Final code (including % notation)
Thanks for the help