title: Qt for Python: Qtreeview from a Dictionary
body: <p>Using Qt's 'Simple Tree Model Example' as a basis the following builds <em>most</em> of the QTreeView from the given dictionary.</p>
  
  <pre><code>#!/usr/bin/env python
  # -*- coding: utf-8 -*-
  
  import sys
  from PySide2.QtWidgets import QApplication, QWidget, QGroupBox, QHBoxLayout, QVBoxLayout, QTreeView
  from PySide2.QtCore import Qt, QAbstractItemModel, QModelIndex
  
  
  class GUIWindow(QWidget):
      def __init__(self, parent=None):
          super(GUIWindow, self).__init__(parent)
          """ Setup UI """
  
          self.setWindowTitle("QTreeView from Dictionary")
  
          groupbox_model = QGroupBox('TreeView')  # Create a Group Box for the Model
  
          hbox_model = QHBoxLayout()  # Create a Horizontal layout for the Model
          vbox = QVBoxLayout()  # Create a Vertical layout for the Model Horizontal layout
  
          tree_view = QTreeView()    # Instantiate the View
  
          headers = ["Dictionary"]
  
          tree = {'Root': {"Level_1": {"Item_1": 1.10, "Item_2": 1.20, "Item_3": 1.30},
                           "Level_2": {"SubLevel_1":
                                           {"SubLevel_1_item1": 2.11, "SubLevel_1_Item2": 2.12, "SubLevel_1_Item3": 2.13},
                                       "SubLevel_2":
                                           {"SubLevel_2_Item1": 2.21, "SubLevel_2_Item2": 2.22, "SubLevel_2_Item3": 2.23}},
                           "Level_3": {"Item_1": 3.10, "Item_2": 3.20, "Item_3": 3.30}}}
  
          # Set the models
          model = TreeModel(headers, tree)
          tree_view.setModel(model)
  
          hbox_model.addWidget(tree_view)     # Add the Widget to the Model Horizontal layout
          groupbox_model.setLayout(hbox_model)    # Add the hbox_model to layout of group box
          vbox.addWidget(groupbox_model)    # Add groupbox elements to vbox
          self.setLayout(vbox)
  
  
  class TreeModel(QAbstractItemModel):
      def __init__(self, header, data, parent=None):
          super(TreeModel, self).__init__(parent)
          """ subclassing the standard interface item models must use and 
          implementing index(), parent(), rowCount(), columnCount(), and data()."""
  
          rootData = header
          self.rootItem = TreeNode(rootData)
          level = 0
          self.createData(data, level)
  
      def createData(self, data, level):
          parents = [self.rootItem]
          sublevel = 2
  
          if type(data) == dict:
              level += 1
              for key, values in data.items():
                  if level &gt; sublevel:
                      parents.append(parents[-1].child(parents[-1].childCount() - 1))
                  if level &gt; sublevel + 1:
                      sublevel += 1
                      if level &gt; sublevel:
                          parents.append(parents[-1].child(parents[-1].childCount() - 1))
                  # Append a new item to the current parent's list of children
                  parent_item = parents[-1]
                  parent_item.insertChildren(parent_item.childCount())
                  parent_item.child(parent_item.childCount() - 1).setData([key])
  
                  self.createData(values, level)    # Recursion to iterate through nested dict
                  sublevel += 1
  
      def index(self, row, column, index=QModelIndex()):
          """ Returns the index of the item in the model specified by the given row, column and parent index """
  
          if not self.hasIndex(row, column, index):
              return QModelIndex()
          if not index.isValid():
              item = self.rootItem
          else:
              item = index.internalPointer()
  
          child = item.child(row)
          if child:
              return self.createIndex(row, column, child)
          return QModelIndex()
  
      def parent(self, index):
          """ Returns the parent of the model item with the given index
          If the item has no parent, an invalid QModelIndex is returned """
  
          if not index.isValid():
              return QModelIndex()
          item = index.internalPointer()
          if not item:
              return QModelIndex()
  
          parent = item.parentItem
          if parent == self.rootItem:
              return QModelIndex()
          else:
              return self.createIndex(parent.childNumber(), 0, parent)
  
      def rowCount(self, index=QModelIndex()):
          """ Returns the number of rows under the given parent
          When the parent is valid it means that rowCount is returning the number of children of parent """
  
          parent = self.getItem(index)
          return parent.childCount()
  
      def columnCount(self, index=QModelIndex()):
          """ Returns the number of columns for the children of the given parent """
  
          if index.isValid():
              return index.internalPointer().columnCount()
          else:
              return self.rootItem.columnCount()
  
      def data(self, index, role=Qt.DisplayRole):
          """ Returns the data stored under the given role for the item referred to by the index """
  
          if index.isValid() and role == Qt.DisplayRole:
              return index.internalPointer().data(index.column())
          elif not index.isValid():
              return self.rootItem.getData()
  
      def getItem(self, index):
          """ Retrieves the tree node with a given index """
  
          if index.isValid():
              item = index.internalPointer()
              if item:
                  return item
          return self.rootItem
  
      def headerData(self, section, orientation, role):
          """ Returns the data for the given role and section in the header with the specified orientation """
  
          if orientation == Qt.Horizontal and role == Qt.DisplayRole:
              return self.rootItem.data(section)
  
  
  class TreeNode(object):
      def __init__(self, data, parent=None):
  
          self.parentItem = parent
          self.itemData = data
          self.children = []
  
      def child(self, row):
          return self.children[row]
  
      def childCount(self):
          return len(self.children)
  
      def childNumber(self):
          if self.parentItem:
              return self.parentItem.children.index(self)
          return 0
  
      def columnCount(self):
          return 1
  
      def data(self, column):
          return self.itemData[column]
  
      def insertChildren(self, position):
          item = TreeNode([1], self)
          self.children.insert(position, item)
          return True
  
      def parent(self):
          return self.parentItem
  
      def setData(self, value):
          self.itemData[0] = value
          return True
  
  
  if __name__ == '__main__':
      app = QApplication(sys.argv)
      app.setStyle("plastique")  # ("cleanlooks")
      form = GUIWindow()
      form.show()
      sys.exit(app.exec_())
  </code></pre>
  
  <p>Is the above a good approach?</p>
  
  <p>And what code (required/changes) would be necessary to:</p>
  
  <ol>
  <li><p>Get 'Root' as the top level?</p></li>
  <li><p>Show the 'values' e.g. 1.10 for key 'Item_1' as the child of 'Item_1'?</p></li>
  </ol>
  
  <p>Appreciate suggestions.</p>