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.
  • 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
                                    • S Stan Pamela

                                      @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 Offline
                                      S Offline
                                      Stan Pamela
                                      wrote on last edited by
                                      #21

                                      Thanks again so much @SGaist , @friedemannkleint and @mpergand for the help and patience. Just for the record, here are the details for a working example, based on the original https://doc.qt.io/qtforpython-6/examples/example_widgets_itemviews_editabletreemodel.html

                                      ======================
                                      mainwindow.py:

                                      # Copyright (C) 2022 The Qt Company Ltd.
                                      # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
                                      
                                      import sys
                                      from pathlib import Path
                                      
                                      from PySide6.QtCore import (QAbstractItemModel, QItemSelectionModel,
                                                                  QModelIndex, Qt, Slot)
                                      from PySide6.QtWidgets import (QAbstractItemView, QMainWindow, QTreeView,
                                                                     QWidget)
                                      from PySide6.QtGui import QFont
                                      from PySide6.QtTest import QAbstractItemModelTester
                                      
                                      from treemodel import TreeModel
                                      
                                      
                                      class MainWindow(QMainWindow):
                                          def __init__(self, parent: QWidget = None):
                                              super().__init__(parent)
                                              self.resize(573, 468)
                                      
                                              self.view = QTreeView()
                                              self.view.setAlternatingRowColors(True)
                                              self.view.setSelectionBehavior(QAbstractItemView.SelectItems)
                                              self.view.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
                                              self.view.setAnimated(False)
                                              self.view.setAllColumnsShowFocus(True)
                                              self.setCentralWidget(self.view)
                                      
                                              menubar = self.menuBar()
                                              file_menu = menubar.addMenu("&File")
                                              self.exit_action = file_menu.addAction("E&xit")
                                              self.exit_action.setShortcut("Ctrl+Q")
                                              self.exit_action.triggered.connect(self.close)
                                      
                                              actions_menu = menubar.addMenu("&Actions")
                                              actions_menu.triggered.connect(self.update_actions)
                                              self.insert_row_action = actions_menu.addAction("Insert Row")
                                              self.insert_row_action.setShortcut("Ctrl+I, R")
                                              self.insert_row_action.triggered.connect(self.insert_row)
                                              self.insert_column_action = actions_menu.addAction("Insert Column")
                                              self.insert_column_action.setShortcut("Ctrl+I, C")
                                              self.insert_column_action.triggered.connect(self.insert_column)
                                              actions_menu.addSeparator()
                                              self.remove_row_action = actions_menu.addAction("Remove Row")
                                              self.remove_row_action.setShortcut("Ctrl+R, R")
                                              self.remove_row_action.triggered.connect(self.remove_row)
                                              self.remove_column_action = actions_menu.addAction("Remove Column")
                                              self.remove_column_action.setShortcut("Ctrl+R, C")
                                              self.remove_column_action.triggered.connect(self.remove_column)
                                              actions_menu.addSeparator()
                                              self.insert_child_action = actions_menu.addAction("Insert Child")
                                              self.insert_child_action.setShortcut("Ctrl+N")
                                              self.insert_child_action.triggered.connect(self.insert_child)
                                              help_menu = menubar.addMenu("&Help")
                                              about_qt_action = help_menu.addAction("About Qt", qApp.aboutQt)
                                              about_qt_action.setShortcut("F1")
                                      
                                              self.setWindowTitle("Editable Tree Model")
                                      
                                              headers = ["Title", "Description"]
                                      
                                              file = Path(__file__).parent / "default.txt"
                                              self.model = TreeModel(headers, file.read_text(), self)
                                      
                                              if "-t" in sys.argv:
                                                  QAbstractItemModelTester(self.model, self)
                                              self.view.setModel(self.model)
                                              self.view.expandAll()
                                      
                                              for column in range(self.model.columnCount()):
                                                  self.view.resizeColumnToContents(column)
                                      
                                              selection_model = self.view.selectionModel()
                                              selection_model.selectionChanged.connect(self.update_actions)
                                      
                                              self.update_actions()
                                      
                                          @Slot()
                                          def insert_child(self) -> None:
                                              selection_model = self.view.selectionModel()
                                              index: QModelIndex = selection_model.currentIndex()
                                              model: QAbstractItemModel = self.view.model()
                                      
                                              if model.columnCount(index) == 0:
                                                  if not model.insertColumn(0, index):
                                                      return
                                      
                                              if not model.insertRow(0, index):
                                                  return
                                      
                                              for column in range(model.columnCount(index)):
                                                  child: QModelIndex = model.index(0, column, index)
                                                  model.setData(child, "[No data]", Qt.EditRole)
                                                  if not model.headerData(column, Qt.Horizontal):
                                                      model.setHeaderData(column, Qt.Horizontal, "[No header]",
                                                                          Qt.EditRole)
                                      
                                              selection_model.setCurrentIndex(
                                                  model.index(0, 0, index), QItemSelectionModel.ClearAndSelect
                                              )
                                              self.update_actions()
                                      
                                          @Slot()
                                          def insert_column(self) -> None:
                                              model: QAbstractItemModel = self.view.model()
                                              column: int = self.view.selectionModel().currentIndex().column()
                                      
                                              changed: bool = model.insertColumn(column + 1)
                                              if changed:
                                                  model.setHeaderData(column + 1, Qt.Horizontal, "[No header]",
                                                                      Qt.EditRole)
                                      
                                              self.update_actions()
                                      
                                          @Slot()
                                          def insert_row(self) -> None:
                                              index: QModelIndex = self.view.selectionModel().currentIndex()
                                              model: QAbstractItemModel = self.view.model()
                                              parent: QModelIndex = index.parent()
                                      
                                              if not model.insertRow(index.row() + 1, parent):
                                                  return
                                      
                                              self.update_actions()
                                      
                                              for column in range(model.columnCount(parent)):
                                                  child: QModelIndex = model.index(index.row() + 1, column, parent)
                                                  model.setData(child, "[No data]", Qt.EditRole)
                                      
                                          @Slot()
                                          def remove_column(self) -> None:
                                              model: QAbstractItemModel = self.view.model()
                                              column: int = self.view.selectionModel().currentIndex().column()
                                      
                                              if model.removeColumn(column):
                                                  self.update_actions()
                                      
                                          @Slot()
                                          def remove_row(self) -> None:
                                              index: QModelIndex = self.view.selectionModel().currentIndex()
                                              model: QAbstractItemModel = self.view.model()
                                      
                                              if model.removeRow(index.row(), index.parent()):
                                                  self.update_actions()
                                      
                                          @Slot()
                                          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)
                                      
                                              model: QAbstractItemModel = self.view.model()
                                              newFont = QFont("Times New Roman", 20, QFont.Bold)
                                              newFont.setItalic(True)
                                              model.setData(current_index, newFont, role=Qt.FontRole)
                                      
                                              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)
                                      

                                      ======================
                                      treeitem.py:

                                      # Copyright (C) 2022 The Qt Company Ltd.
                                      # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
                                      
                                      
                                      class TreeItem:
                                          def __init__(self, data: list, parent: 'TreeItem' = None):
                                              self.item_data = data
                                              self.item_font = [None] * len(data)
                                              self.parent_item = parent
                                              self.child_items = []
                                      
                                          def child(self, number: int) -> 'TreeItem':
                                              if number < 0 or number >= len(self.child_items):
                                                  return None
                                              return self.child_items[number]
                                      
                                          def last_child(self):
                                              return self.child_items[-1] if self.child_items else None
                                      
                                          def child_count(self) -> int:
                                              return len(self.child_items)
                                      
                                          def child_number(self) -> int:
                                              if self.parent_item:
                                                  return self.parent_item.child_items.index(self)
                                              return 0
                                      
                                          def column_count(self) -> int:
                                              return len(self.item_data)
                                      
                                          def font(self, column: int):
                                              if column < 0 or column >= len(self.item_data):
                                                  return None
                                              return self.item_font[column]
                                      
                                          def data(self, column: int):
                                              if column < 0 or column >= len(self.item_data):
                                                  return None
                                              return self.item_data[column]
                                      
                                          def insert_children(self, position: int, count: int, columns: int) -> bool:
                                              if position < 0 or position > len(self.child_items):
                                                  return False
                                      
                                              for row in range(count):
                                                  data = [None] * columns
                                                  item = TreeItem(data.copy(), self)
                                                  self.child_items.insert(position, item)
                                      
                                              return True
                                      
                                          def insert_columns(self, position: int, columns: int) -> bool:
                                              if position < 0 or position > len(self.item_data):
                                                  return False
                                      
                                              for column in range(columns):
                                                  self.item_data.insert(position, None)
                                      
                                              for child in self.child_items:
                                                  child.insert_columns(position, columns)
                                      
                                              return True
                                      
                                          def parent(self):
                                              return self.parent_item
                                      
                                          def remove_children(self, position: int, count: int) -> bool:
                                              if position < 0 or position + count > len(self.child_items):
                                                  return False
                                      
                                              for row in range(count):
                                                  self.child_items.pop(position)
                                      
                                              return True
                                      
                                          def remove_columns(self, position: int, columns: int) -> bool:
                                              if position < 0 or position + columns > len(self.item_data):
                                                  return False
                                      
                                              for column in range(columns):
                                                  self.item_data.pop(position)
                                      
                                              for child in self.child_items:
                                                  child.remove_columns(position, columns)
                                      
                                              return True
                                      
                                          def set_font(self, column: int, value):
                                              if column < 0 or column >= len(self.item_data):
                                                  return False
                                      
                                              self.item_font[column] = value
                                              return True
                                      
                                          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
                                      

                                      ======================
                                      treemodel.py:

                                      # Copyright (C) 2022 The Qt Company Ltd.
                                      # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
                                      
                                      
                                      from PySide6.QtCore import QModelIndex, Qt, QAbstractItemModel
                                      from treeitem import TreeItem
                                      
                                      
                                      class TreeModel(QAbstractItemModel):
                                      
                                          def __init__(self, headers: list, data: str, parent=None):
                                              super().__init__(parent)
                                      
                                              self.root_data = headers
                                              self.root_item = TreeItem(self.root_data.copy())
                                              self.setup_model_data(data.split("\n"), self.root_item)
                                      
                                          def columnCount(self, parent: QModelIndex = None) -> int:
                                              return self.root_item.column_count()
                                      
                                          def data(self, index: QModelIndex, role: int = None):
                                              if not index.isValid():
                                                  return None
                                      
                                              if role != Qt.DisplayRole and role != Qt.EditRole and role != Qt.FontRole:
                                                  return None
                                      
                                              item: TreeItem = self.get_item(index)
                                      
                                              if role == Qt.FontRole:
                                                  return item.font(index.column())
                                      
                                              return item.data(index.column())
                                      
                                          def flags(self, index: QModelIndex) -> Qt.ItemFlags:
                                              if not index.isValid():
                                                  return Qt.NoItemFlags
                                      
                                              return Qt.ItemIsEditable | QAbstractItemModel.flags(self, index)
                                      
                                          def get_item(self, index: QModelIndex = QModelIndex()) -> TreeItem:
                                              if index.isValid():
                                                  item: TreeItem = index.internalPointer()
                                                  if item:
                                                      return item
                                      
                                              return self.root_item
                                      
                                          def headerData(self, section: int, orientation: Qt.Orientation,
                                                         role: int = Qt.DisplayRole):
                                              if orientation == Qt.Horizontal and role == Qt.DisplayRole:
                                                  return self.root_item.data(section)
                                      
                                              return None
                                      
                                          def index(self, row: int, column: int, parent: QModelIndex = QModelIndex()) -> QModelIndex:
                                              if parent.isValid() and parent.column() != 0:
                                                  return QModelIndex()
                                      
                                              parent_item: TreeItem = self.get_item(parent)
                                              if not parent_item:
                                                  return QModelIndex()
                                      
                                              child_item: TreeItem = parent_item.child(row)
                                              if child_item:
                                                  return self.createIndex(row, column, child_item)
                                              return QModelIndex()
                                      
                                          def insertColumns(self, position: int, columns: int,
                                                            parent: QModelIndex = QModelIndex()) -> bool:
                                              self.beginInsertColumns(parent, position, position + columns - 1)
                                              success: bool = self.root_item.insert_columns(position, columns)
                                              self.endInsertColumns()
                                      
                                              return success
                                      
                                          def insertRows(self, position: int, rows: int,
                                                         parent: QModelIndex = QModelIndex()) -> bool:
                                              parent_item: TreeItem = self.get_item(parent)
                                              if not parent_item:
                                                  return False
                                      
                                              self.beginInsertRows(parent, position, position + rows - 1)
                                              column_count = self.root_item.column_count()
                                              success: bool = parent_item.insert_children(position, rows, column_count)
                                              self.endInsertRows()
                                      
                                              return success
                                      
                                          def parent(self, index: QModelIndex = QModelIndex()) -> QModelIndex:
                                              if not index.isValid():
                                                  return QModelIndex()
                                      
                                              child_item: TreeItem = self.get_item(index)
                                              if child_item:
                                                  parent_item: TreeItem = child_item.parent()
                                              else:
                                                  parent_item = None
                                      
                                              if parent_item == self.root_item or not parent_item:
                                                  return QModelIndex()
                                      
                                              return self.createIndex(parent_item.child_number(), 0, parent_item)
                                      
                                          def removeColumns(self, position: int, columns: int,
                                                            parent: QModelIndex = QModelIndex()) -> bool:
                                              self.beginRemoveColumns(parent, position, position + columns - 1)
                                              success: bool = self.root_item.remove_columns(position, columns)
                                              self.endRemoveColumns()
                                      
                                              if self.root_item.column_count() == 0:
                                                  self.removeRows(0, self.rowCount())
                                      
                                              return success
                                      
                                          def removeRows(self, position: int, rows: int,
                                                         parent: QModelIndex = QModelIndex()) -> bool:
                                              parent_item: TreeItem = self.get_item(parent)
                                              if not parent_item:
                                                  return False
                                      
                                              self.beginRemoveRows(parent, position, position + rows - 1)
                                              success: bool = parent_item.remove_children(position, rows)
                                              self.endRemoveRows()
                                      
                                              return success
                                      
                                          def rowCount(self, parent: QModelIndex = QModelIndex()) -> int:
                                              if parent.isValid() and parent.column() > 0:
                                                  return 0
                                      
                                              parent_item: TreeItem = self.get_item(parent)
                                              if not parent_item:
                                                  return 0
                                              return parent_item.child_count()
                                      
                                          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)
                                              if role == Qt.FontRole:
                                                  result: bool = item.set_font(index.column(), value)
                                              else:
                                                  result: bool = item.set_data(index.column(), value)
                                      
                                              if result:
                                                  self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole, Qt.FontRole])
                                      
                                              return result
                                      
                                          def setHeaderData(self, section: int, orientation: Qt.Orientation, value,
                                                            role: int = None) -> bool:
                                              if role != Qt.EditRole or orientation != Qt.Horizontal:
                                                  return False
                                      
                                              result: bool = self.root_item.set_data(section, value)
                                      
                                              if result:
                                                  self.headerDataChanged.emit(orientation, section, section)
                                      
                                              return result
                                      
                                          def setup_model_data(self, lines: list, parent: TreeItem):
                                              parents = [parent]
                                              indentations = [0]
                                      
                                              for line in lines:
                                                  line = line.rstrip()
                                                  if line and "\t" in line:
                                      
                                                      position = 0
                                                      while position < len(line):
                                                          if line[position] != " ":
                                                              break
                                                          position += 1
                                      
                                                      column_data = line[position:].split("\t")
                                                      column_data = [string for string in column_data if string]
                                      
                                                      if position > indentations[-1]:
                                                          if parents[-1].child_count() > 0:
                                                              parents.append(parents[-1].last_child())
                                                              indentations.append(position)
                                                      else:
                                                          while position < indentations[-1] and parents:
                                                              parents.pop()
                                                              indentations.pop()
                                      
                                                      parent: TreeItem = parents[-1]
                                                      col_count = self.root_item.column_count()
                                                      parent.insert_children(parent.child_count(), 1, col_count)
                                      
                                                      for column in range(len(column_data)):
                                                          child = parent.last_child()
                                                          child.set_data(column, column_data[column])
                                      
                                          def _repr_recursion(self, item: TreeItem, indent: int = 0) -> str:
                                              result = " " * indent + repr(item) + "\n"
                                              for child in item.child_items:
                                                  result += self._repr_recursion(child, indent + 2)
                                              return result
                                      
                                          def __repr__(self) -> str:
                                              return self._repr_recursion(self.root_item)
                                      
                                      1 Reply Last reply
                                      0
                                      • S Stan Pamela has marked this topic as solved on

                                      • Login

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