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
Forum Updated to NodeBB v4.3 + New Features

Changing Font and background color of individual item in editable Treeview

Scheduled Pinned Locked Moved Solved Qt for Python
21 Posts 4 Posters 4.4k 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