0

I have a data structure which essentially amounts to a nested dictionary. Let's say it looks like this:

standard_dict = {
        'section1': {
            'category1': np.array([1, 2, 3, 5]),
            'category2': 2
        },
        'section2': {
             'category1': [4, 5, 6],
             'category2': {'category2a': {'t': 1}}
        }
    }

Furthermore I have a recursive function with a for loop to generate a nested treeview out of this dictionary. Now I'm trying to ad in the for loop an index to every value, key pair. I tried it with QModelindex but I didn't get to the point where the code does what i want it to.

    def add_object(self, v: object, prefix1: object) -> object:
        if isinstance(v, dict):
            for k, v2 in v.items():
                prefix1.addChild(CustomNode(k))
                prefix = prefix1.getlastChild()
                self.add_object(v2, prefix)
                
        elif isinstance(v, list):
            for e in v:
                prefix1.addChild(CustomNode(e))

Is there an simple way to implement and add the index to the value, key pair?

The result i'd like to have is to update only the changed single values in a PyQt5 Gui an not the whole Gui.

Here is my whole Project if someone wants to know.

"""
import copy
from typing import List, Any
import sys
from PyQt5 import QtCore, QtWidgets, uic
import numpy as np
from deepdiff import DeepDiff
from lib.MainWindow import Ui_MainWindow


class CustomNode(object):
    def __init__(self, data):
        self._data = data
        if type(data) == tuple:
            self._data = list(data)
        if type(data) is str or not hasattr(data, '__getitem__'):
            self._data = [data]

        self._columncount = len(self._data)
        self._children = []
        self._parent = None
        self._row = 0

    def getlastChild(self):
        return self._children[-1]

    def data(self, column):
        if column >= 0 and column < len(self._data):
            return self._data[column]

    def columnCount(self):
        return self._columncount

    def childCount(self):
        return len(self._children)

    def child(self, row):
        if row >= 0 and row < self.childCount():
            return self._children[row]

    def parent(self):
        return self._parent

    def row(self):
        return self._row

    def addChild(self, child):
        child._parent = self
        child._row = len(self._children)
        self._children.append(child)
        self._columncount = max(child.columnCount(), self._columncount)


class CustomModel(QtCore.QAbstractItemModel):
    def __init__(self, nodes):
        QtCore.QAbstractItemModel.__init__(self)
        self._root = CustomNode(None)
        for node in nodes:
            self._root.addChild(node)

    def rowCount(self, index: object) -> object:
        if index.isValid():
            return index.internalPointer().childCount()
        return self._root.childCount()

    def addChild(self, node, _parent):
        if not _parent or not _parent.isValid():
            parent = self._root
        else:
            parent = _parent.internalPointer()
        parent.addChild(node)

    def index(self, row, column, _parent=None):
        if not _parent or not _parent.isValid():
            parent = self._root
        else:
            parent = _parent.internalPointer()

        if not QtCore.QAbstractItemModel.hasIndex(self, row, column, _parent):
            return QtCore.QModelIndex()

        child = parent.child(row)
        if child:
            return QtCore.QAbstractItemModel.createIndex(self, row, column, child)
        else:
            return QtCore.QModelIndex()

    def parent(self, index):
        if index.isValid():
            p = index.internalPointer().parent()
            if p:
                return QtCore.QAbstractItemModel.createIndex(self, p.row(), 0, p)
        return QtCore.QModelIndex()

    def columnCount(self, index):
        if index.isValid():
            return index.internalPointer().columnCount()
        return self._root.columnCount()

    def data(self, index, role):
        if not index.isValid():
            return None
        node = index.internalPointer()
        if role == QtCore.Qt.DisplayRole:
            return node.data(index.column())
        return None


class MyTree():

    def __init__(self, ref_dict, treeView):
        self.items = []
        self.ref_dict = ref_dict
        self.items = []
        self.index_dict = ref_dict


        '''Erzeugt eine List aus den Hauptitems'''
        for key in self.ref_dict:
            self.items += [CustomNode(key)]
            self.add_object(self.ref_dict[key], prefix1=self.items[-1])

        '''Aufruf der View um die Anzeige darzustellen'''
        # self.tw = QtWidgets.QTreeView()
        self.tw = treeView
        self.tw.setModel(CustomModel(self.items)) #referenz auf das Modell, gibt das Modell zurück
        print(self.tw.model())

    '''Funktion um das Dictionary zu iterieren und in einer Treeview darzustellen'''
    def add_object(self, v: object, prefix1: object) -> object:
        if isinstance(v, dict):
            for k, v2 in v.items():
                prefix1.addChild(CustomNode(k))
                prefix = prefix1.getlastChild()
                self.add_object(v2, prefix)
                
        elif isinstance(v, list):
            for e in v:
                prefix1.addChild(CustomNode(e))

        elif isinstance(v, type(np.array([]))):
            [prefix1.addChild(CustomNode(int(i))) for i in v]

        else:
            prefix1.addChild(CustomNode(v))

    

class Compare():
    def __init__(self, standard_dict):
        self.__standard_dict = copy.deepcopy(standard_dict)

    @property
    def standard_dict(self):
        return self.__standard_dict

    @standard_dict.setter
    def standard_dict(self, standard_dict):
        self.__standard_dict = standard_dict
        # Signal auslösen mit kompletten Update vom Model

    '''Funktion um mit DeepDiff die beiden Dictionaries zu vergleichen'''
    def compare(self, new_dict):
        return DeepDiff(self.__standard_dict, new_dict)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        mytree = MyTree(standard_dict, self.ui.treeView)
        mytree_2 = MyTree(standard_dict, self.ui.treeView_2)
        self.ui.pushButton.clicked.connect(self.compare_dict)
        self.comp = Compare(standard_dict=standard_dict)

    def compare_dict(self):
        standard_dict['section1']['category2'] += 1
        diff = self.comp.compare(standard_dict)
        self.ui.plainTextEdit.insertPlainText(str(standard_dict))
        self.ui.plainTextEdit.insertPlainText(str(diff))
        #mytree_3 = MyTree(standard_dict, self.ui.treeView_2)
        #nur die Stelle des geänderten Indexes updaten und keine neue View erstellen


if __name__ == "__main__":

    standard_dict = {
        'section1': {
            'category1': np.array([1, 2, 3, 5]),
            'category2': 2
        },
        'section2': {
             'category1': [4, 5, 6],
             'category2': {'category2a': {'t': 1}}
        }
    }

    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

Thanks a lot in advance

aeschcol
  • 1
  • 1
  • [How to iterate `dict` with `enumerate` and unpack the index, key, and value along with iteration](https://stackoverflow.com/questions/42193712/how-to-iterate-dict-with-enumerate-and-unpack-the-index-key-and-value-alon) may be of use. – hemmelig Jun 24 '20 at 14:11
  • Thanks for your advice. I've read this post, but when I append the Index in my for loop then the Index shows only the values 0 and 1. def add_object(self, v: object, prefix1: object) -> object: if isinstance(v, dict): for i, (k, v2) in enumerate(v.items()): prefix1.addChild(CustomNode(k)) prefix1.addChild(CustomNode(i)) prefix = prefix1.getlastChild() print("index: {}, key: {}, value:{}".format(i, k, v2)) self.add_object(v2, prefix) – aeschcol Jun 25 '20 at 07:32

0 Answers0