Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. QItemDelegate: colour all text in cells of a row
Forum Update on Monday, May 27th 2025

QItemDelegate: colour all text in cells of a row

Scheduled Pinned Locked Moved Solved Qt for Python
8 Posts 2 Posters 1.8k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    Liamdale
    wrote on last edited by
    #1

    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:
    0_1564840366290_bikeResults-img.png

    "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.

    1 Reply Last reply
    0
    • Erudite MonkeyE Offline
      Erudite MonkeyE Offline
      Erudite Monkey
      wrote on last edited by Erudite Monkey
      #2

      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)
      
      1 Reply Last reply
      0
      • L Offline
        L Offline
        Liamdale
        wrote on last edited by
        #3

        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?

        1 Reply Last reply
        0
        • Erudite MonkeyE Offline
          Erudite MonkeyE Offline
          Erudite Monkey
          wrote on last edited by Erudite Monkey
          #4

          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) > 100
          

          As for the error, I don't think PyQt4 has any siblingAtColumn method for model indexes, They are in PySide2. Since this looks empty idk if its in pyqt5 either..

          or 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)
          
          1 Reply Last reply
          0
          • L Offline
            L Offline
            Liamdale
            wrote on last edited by Liamdale
            #5

            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.1

            Do 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 ???

            1 Reply Last reply
            0
            • Erudite MonkeyE Offline
              Erudite MonkeyE Offline
              Erudite Monkey
              wrote on last edited by Erudite Monkey
              #6

              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 pyside2
              

              I'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)
              
              1 Reply Last reply
              0
              • L Offline
                L Offline
                Liamdale
                wrote on last edited by
                #7

                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.

                L 1 Reply Last reply
                0
                • L Liamdale

                  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.

                  L Offline
                  L Offline
                  Liamdale
                  wrote on last edited by Liamdale
                  #8

                  @liamdale

                  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
                  0_1565401060940_Colour foreground.png

                  Final code (including % notation)
                  Thanks for the help

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved