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. Changing Font and background color of individual item in editable Treeview

Changing Font and background color of individual item in editable Treeview

Scheduled Pinned Locked Moved Solved Qt for Python
21 Posts 4 Posters 5.6k Views 3 Watching
  • 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.
  • S Offline
    S Offline
    Stan Pamela
    wrote on last edited by Stan Pamela
    #1

    Hi all,

    I'm quite new to Qt, and I've had a lot of fun playing with the Editable Treeview example: https://doc.qt.io/qtforpython-6/examples/example_widgets_itemviews_editabletreemodel.html

    But I'm struggling to find out how to change the formatting of individual cells. For example the font-size or the background color. I found how to change the font for the entire treeview, or just the headers, but not for individual items.

    As a starting minimal case, I can edit the last routine of mainwindow.py as follows to change the text of that cell to say "hello":

    def update_actions(self) -> None:
        selection_model = self.view.selectionModel()
        has_selection: bool = not selection_model.selection().isEmpty()
        self.remove_row_action.setEnabled(has_selection)
        self.remove_column_action.setEnabled(has_selection)
    
        current_index = selection_model.currentIndex()
        has_current: bool = current_index.isValid()
        self.insert_row_action.setEnabled(has_current)
        self.insert_column_action.setEnabled(has_current)
    
        # say hello
        model: QAbstractItemModel = self.view.model()
        model.setData(current_index, "hello", Qt.EditRole)
    
        if has_current:
            self.view.closePersistentEditor(current_index)
            msg = f"Position: ({current_index.row()},{current_index.column()})"
            if not current_index.parent().isValid():
                msg += " in top level"
            self.statusBar().showMessage(msg)
    

    Would anybody be able to help me change the font and background color of that specific item instead of just setting item to "hello", please?

    Thanks a lot in advance!

    1 Reply Last reply
    0
    • F Offline
      F Offline
      friedemannkleint
      wrote on last edited by
      #2

      There are some item roles that influence the styling: https://doc.qt.io/qtforpython-6/PySide6/QtCore/Qt.html#PySide6.QtCore.PySide6.QtCore.Qt.ItemDataRole ( FontRole , TextAlignmentRole , BackgroundRole , ForegroundRole ) . You can return values for them from QAbstractItemModel.data().

      S 1 Reply Last reply
      1
      • F friedemannkleint

        There are some item roles that influence the styling: https://doc.qt.io/qtforpython-6/PySide6/QtCore/Qt.html#PySide6.QtCore.PySide6.QtCore.Qt.ItemDataRole ( FontRole , TextAlignmentRole , BackgroundRole , ForegroundRole ) . You can return values for them from QAbstractItemModel.data().

        S Offline
        S Offline
        Stan Pamela
        wrote on last edited by
        #3

        @friedemannkleint said in Changing Font and background color of individual item in editable Treeview:

        QAbstractItemModel

        Thanks a lot for your help (again ;) Friedmann!

        OK, so I can get a print of various Roles, which are "None" for the most part, simply because they are not set in the first place I assume. However, I cannot change these, because the Tree-model class has a wrapper that replaces the setData function. This is in treemodel.py

        def setData(self, index: QModelIndex, value, role: int) -> bool:
            if role != Qt.EditRole:
                return False
        
            item: TreeItem = self.get_item(index)
            result: bool = item.set_data(index.column(), value)
                
            if result:
                self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole])
        
            return result
        

        where clearly it only deals with the Edit role. I assume I would need to change that function directly? Would you have any advice on how to do that? Thanks !

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Hi,

          The most straightforward would be to modify your first if and expand its check, the rest is the same.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          S 1 Reply Last reply
          0
          • SGaistS SGaist

            Hi,

            The most straightforward would be to modify your first if and expand its check, the rest is the same.

            S Offline
            S Offline
            Stan Pamela
            wrote on last edited by
            #5

            Thanks @SGaist for helping out!

            That doesn't seem to work. If use

                model.setData(current_index, 'QWidget { font: bold italic large "Times New Roman"; font-size: 10pt }', role=Qt.FontRole)
            

            inside the update_actions function of mainwindow.py, together with

                if (role != Qt.EditRole) and (role != Qt.FontRole):
            

            inside the setData function of treemodel.py, what happens is that it just replaces the text of the item by

            'QWidget { font: bold italic large "Times New Roman"; font-size: 10pt }'
            

            as if that was a normal edit action. I think this is because the editable tree version has a whole wrapper of the data itself around it...

            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #6

              It looks like you are trying to set a style sheet in the font role.

              The FontRole takes a QFont object.

              You can see here more information about the roles and what they expect.

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              S 1 Reply Last reply
              0
              • SGaistS SGaist

                It looks like you are trying to set a style sheet in the font role.

                The FontRole takes a QFont object.

                You can see here more information about the roles and what they expect.

                S Offline
                S Offline
                Stan Pamela
                wrote on last edited by
                #7

                Ah. good point. But it still does the same. If I use

                    newFont = QFont("Helvetica")
                    model.setData(current_index, newFont, role=Qt.FontRole)
                

                It just replaces the content of the item with the text "Helvetica"...

                SGaistS M 2 Replies Last reply
                0
                • S Stan Pamela

                  Ah. good point. But it still does the same. If I use

                      newFont = QFont("Helvetica")
                      model.setData(current_index, newFont, role=Qt.FontRole)
                  

                  It just replaces the content of the item with the text "Helvetica"...

                  SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  @Stan-Pamela do you also have a custom data function ?

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  S 1 Reply Last reply
                  1
                  • S Stan Pamela

                    Ah. good point. But it still does the same. If I use

                        newFont = QFont("Helvetica")
                        model.setData(current_index, newFont, role=Qt.FontRole)
                    

                    It just replaces the content of the item with the text "Helvetica"...

                    M Offline
                    M Offline
                    mpergand
                    wrote on last edited by mpergand
                    #9

                    @Stan-Pamela
                    You need to return the right data for the roles in data() not setData()

                    1 Reply Last reply
                    0
                    • SGaistS SGaist

                      @Stan-Pamela do you also have a custom data function ?

                      S Offline
                      S Offline
                      Stan Pamela
                      wrote on last edited by Stan Pamela
                      #10

                      @SGaist yes, it's

                      def data(self, index: QModelIndex, role: int = None):
                          if not index.isValid():
                              return None
                      
                          #if role == Qt.FontRole: # sorry please ignore! that was confusing...
                          #   return item.data(index.column())
                      
                          if role != Qt.DisplayRole and role != Qt.EditRole:
                              return None
                      
                          item: TreeItem = self.get_item(index)
                      
                          return item.data(index.column())
                      

                      which then goes to treeitem.py -> data

                      def data(self, column: int):
                          if column < 0 or column >= len(self.item_data):
                              return None
                          return self.item_data[column]
                      

                      in other words, it's wrapping a TreeItem to get item_data[column]. What would I need to target to return the font? or the style or background?

                      SGaistS 1 Reply Last reply
                      0
                      • S Stan Pamela

                        @SGaist yes, it's

                        def data(self, index: QModelIndex, role: int = None):
                            if not index.isValid():
                                return None
                        
                            #if role == Qt.FontRole: # sorry please ignore! that was confusing...
                            #   return item.data(index.column())
                        
                            if role != Qt.DisplayRole and role != Qt.EditRole:
                                return None
                        
                            item: TreeItem = self.get_item(index)
                        
                            return item.data(index.column())
                        

                        which then goes to treeitem.py -> data

                        def data(self, column: int):
                            if column < 0 or column >= len(self.item_data):
                                return None
                            return self.item_data[column]
                        

                        in other words, it's wrapping a TreeItem to get item_data[column]. What would I need to target to return the font? or the style or background?

                        SGaistS Offline
                        SGaistS Offline
                        SGaist
                        Lifetime Qt Champion
                        wrote on last edited by
                        #11

                        @Stan-Pamela you are not passing the role down to your item data call.

                        Interested in AI ? www.idiap.ch
                        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                        S 1 Reply Last reply
                        0
                        • SGaistS SGaist

                          @Stan-Pamela you are not passing the role down to your item data call.

                          S Offline
                          S Offline
                          Stan Pamela
                          wrote on last edited by
                          #12

                          @SGaist
                          :)
                          I can only reply every 600sec apparently because I'm a new user. I think you need to give me a "reputation" to be able to interact faster? :)

                          Anyway, really sorry about last post, that was confusing, I was trying to edit the data function and copy pasted something that wasn't working...

                          Still, these are the two functions that wrap around item_data

                          def setData(self, index: QModelIndex, value, role: int) -> bool:
                              if (role != Qt.EditRole) and (role != Qt.FontRole):
                                  return False
                          
                              item: TreeItem = self.get_item(index)
                              result: bool = item.set_data(index.column(), value)
                          
                              if result:
                                  self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole, Qt.FontRole])
                          
                              return result
                          

                          and

                          def set_data(self, column: int, value):
                              if column < 0 or column >= len(self.item_data):
                                  return False
                          
                              self.item_data[column] = value
                              return True
                          
                          SGaistS 1 Reply Last reply
                          0
                          • S Stan Pamela

                            @SGaist
                            :)
                            I can only reply every 600sec apparently because I'm a new user. I think you need to give me a "reputation" to be able to interact faster? :)

                            Anyway, really sorry about last post, that was confusing, I was trying to edit the data function and copy pasted something that wasn't working...

                            Still, these are the two functions that wrap around item_data

                            def setData(self, index: QModelIndex, value, role: int) -> bool:
                                if (role != Qt.EditRole) and (role != Qt.FontRole):
                                    return False
                            
                                item: TreeItem = self.get_item(index)
                                result: bool = item.set_data(index.column(), value)
                            
                                if result:
                                    self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole, Qt.FontRole])
                            
                                return result
                            

                            and

                            def set_data(self, column: int, value):
                                if column < 0 or column >= len(self.item_data):
                                    return False
                            
                                self.item_data[column] = value
                                return True
                            
                            SGaistS Offline
                            SGaistS Offline
                            SGaist
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13

                            @Stan-Pamela that's another issue: you don't handle the role in your wrapper just the value.

                            Interested in AI ? www.idiap.ch
                            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                            S 1 Reply Last reply
                            1
                            • SGaistS SGaist

                              @Stan-Pamela that's another issue: you don't handle the role in your wrapper just the value.

                              S Offline
                              S Offline
                              Stan Pamela
                              wrote on last edited by
                              #14

                              @SGaist OK, how do I handle the role?
                              Really sorry, I know this is probably so obvious to you all, but I just can't figure it out. It seems this treeview example is a corner case with all the wrappers, isn't it? Or it's just me?

                              Still can't write more than every 600sec :( maybe just as well, ahah!

                              1 Reply Last reply
                              0
                              • SGaistS Offline
                                SGaistS Offline
                                SGaist
                                Lifetime Qt Champion
                                wrote on last edited by
                                #15

                                Ok, I see the issue. The example works well for just handling "data".

                                You need to modify your custom TreeItem to handle the role in addition to the value. As a basic version, you can use a dictionary where the key is the role and the item the value. Add a role parameter to the set_data and data methods so that you can properly set and retrieve these values.

                                Interested in AI ? www.idiap.ch
                                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                S 1 Reply Last reply
                                0
                                • SGaistS SGaist

                                  Ok, I see the issue. The example works well for just handling "data".

                                  You need to modify your custom TreeItem to handle the role in addition to the value. As a basic version, you can use a dictionary where the key is the role and the item the value. Add a role parameter to the set_data and data methods so that you can properly set and retrieve these values.

                                  S Offline
                                  S Offline
                                  Stan Pamela
                                  wrote on last edited by
                                  #16

                                  @SGaist

                                  Thanks again. I'm still not sure how to do that...
                                  Even for the "value" itself, could you explain how/where the final target TreeItem->item_data is set? This doesn't seem to be a standard Qt class/variable... I'm confused...

                                  At the very end of treeitem.py, in this editable tree example, there is this recursive function:

                                  def set_data(self, column: int, value):
                                      if column < 0 or column >= len(self.item_data):
                                          return False
                                  
                                      self.item_data[column] = value
                                      return True
                                  
                                  def __repr__(self) -> str:
                                      result = f"<treeitem.TreeItem at 0x{id(self):x}"
                                      for d in self.item_data:
                                          result += f' "{d}"' if d else " <None>"
                                      result += f", {len(self.child_items)} children>"
                                      return result
                                  

                                  Is it this repr function that's used internally, in the backend of the Qt library, to display the text manually? Do I need to use a similar backend function for the role?

                                  SGaistS 1 Reply Last reply
                                  0
                                  • S Stan Pamela

                                    @SGaist

                                    Thanks again. I'm still not sure how to do that...
                                    Even for the "value" itself, could you explain how/where the final target TreeItem->item_data is set? This doesn't seem to be a standard Qt class/variable... I'm confused...

                                    At the very end of treeitem.py, in this editable tree example, there is this recursive function:

                                    def set_data(self, column: int, value):
                                        if column < 0 or column >= len(self.item_data):
                                            return False
                                    
                                        self.item_data[column] = value
                                        return True
                                    
                                    def __repr__(self) -> str:
                                        result = f"<treeitem.TreeItem at 0x{id(self):x}"
                                        for d in self.item_data:
                                            result += f' "{d}"' if d else " <None>"
                                        result += f", {len(self.child_items)} children>"
                                        return result
                                    

                                    Is it this repr function that's used internally, in the backend of the Qt library, to display the text manually? Do I need to use a similar backend function for the role?

                                    SGaistS Offline
                                    SGaistS Offline
                                    SGaist
                                    Lifetime Qt Champion
                                    wrote on last edited by
                                    #17

                                    Basically:

                                         def set_data(self, column: int, value, role):
                                             if column < 0 or column >= len(self.item_data):
                                                 return False
                                     
                                             if column not in self.item_data.keys():
                                                 self.item_data[column] = {}
                                             self.item_data[column][role] = value
                                             return True
                                    

                                    Don't forget to handle the EditRole and Display role properly.

                                    Interested in AI ? www.idiap.ch
                                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                    S 1 Reply Last reply
                                    0
                                    • SGaistS SGaist

                                      Basically:

                                           def set_data(self, column: int, value, role):
                                               if column < 0 or column >= len(self.item_data):
                                                   return False
                                       
                                               if column not in self.item_data.keys():
                                                   self.item_data[column] = {}
                                               self.item_data[column][role] = value
                                               return True
                                      

                                      Don't forget to handle the EditRole and Display role properly.

                                      S Offline
                                      S Offline
                                      Stan Pamela
                                      wrote on last edited by
                                      #18

                                      That doesn't work either. Or I'm not doing it properly(?)
                                      Even ignoring the font role, and just trying to do the simplest thing possible: to use a dict like this for the text edit alone, and replace the original functionality, it doesn't work:

                                      def set_data(self, column: int, value):
                                          if column < 0 or column >= len(self.item_data):
                                              return False
                                      
                                          #self.item_data[column] = value
                                          self.item_data[column] = {Qt.EditRole: value}
                                      
                                      SGaistS 1 Reply Last reply
                                      0
                                      • S Stan Pamela

                                        That doesn't work either. Or I'm not doing it properly(?)
                                        Even ignoring the font role, and just trying to do the simplest thing possible: to use a dict like this for the text edit alone, and replace the original functionality, it doesn't work:

                                        def set_data(self, column: int, value):
                                            if column < 0 or column >= len(self.item_data):
                                                return False
                                        
                                            #self.item_data[column] = value
                                            self.item_data[column] = {Qt.EditRole: value}
                                        
                                        SGaistS Offline
                                        SGaistS Offline
                                        SGaist
                                        Lifetime Qt Champion
                                        wrote on last edited by
                                        #19

                                        @Stan-Pamela did you adapt the data function in a similar fashion ?

                                        Interested in AI ? www.idiap.ch
                                        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                        S 1 Reply Last reply
                                        0
                                        • SGaistS SGaist

                                          @Stan-Pamela did you adapt the data function in a similar fashion ?

                                          S Offline
                                          S Offline
                                          Stan Pamela
                                          wrote on last edited by
                                          #20

                                          @SGaist, got it!
                                          Thanks so much and sorry it took me so long to understand the trail of wrappers and how that feeds back into the main model. Awesome. I did it in a dirty way for now, but shall I clean up and post a zip of the code for consistency and closure of this forum thread?

                                          Screenshot 2024-01-24 at 22.19.29.png

                                          S 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