Skip to content Skip to sidebar Skip to footer

Qtreewidget To Mirror Python Dictionary

Is there a way to make a QTreeWidget mirror the changes made to an internal data structure such as dictionary? It seems like they would have created this functionality within the

Solution 1:

This is a straightforward implementation:

def fill_item(item, value):
  item.setExpanded(True)
  if type(value) is dict:
    for key, val in sorted(value.iteritems()):
      child = QTreeWidgetItem()
      child.setText(0, unicode(key))
      item.addChild(child)
      fill_item(child, val)
  elif type(value) is list:
    for val in value:
      child = QTreeWidgetItem()
      item.addChild(child)
      if type(val) is dict:      
        child.setText(0, '[dict]')
        fill_item(child, val)
      elif type(val) is list:
        child.setText(0, '[list]')
        fill_item(child, val)
      else:
        child.setText(0, unicode(val))              
      child.setExpanded(True)
  else:
    child = QTreeWidgetItem()
    child.setText(0, unicode(value))
    item.addChild(child)

def fill_widget(widget, value):
  widget.clear()
  fill_item(widget.invisibleRootItem(), value)

I added list support just in case anyone needs it.

Usage:

d = { 'key1': 'value1', 
  'key2': 'value2',
  'key3': [1,2,3, { 1: 3, 7 : 9}],
  'key4': object(),
  'key5': { 'another key1' : 'another value1',
            'another key2' : 'another value2'} }

widget = QTreeWidget()
fill_widget(widget, d)
widget.show()

Result:

screenshot

Solution 2:

Just because I recently needed this implementation for Python3 and PyQt5 here is a slightly shorter (and complete) port of the given example:

from PyQt5.QtWidgets import  QApplication, QTreeWidget, QTreeWidgetItem

classViewTree(QTreeWidget):
    def__init__(self, value):
        super().__init__()
        deffill_item(item, value):
            defnew_item(parent, text, val=None):
                child = QTreeWidgetItem([text])
                fill_item(child, val)
                parent.addChild(child)
                child.setExpanded(True)
            if value isNone: returnelifisinstance(value, dict):
                for key, val insorted(value.items()):
                    new_item(item, str(key), val)
            elifisinstance(value, (list, tuple)):
                for val in value:
                    text = (str(val) ifnotisinstance(val, (dict, list, tuple))
                            else'[%s]' % type(val).__name__)
                    new_item(item, text, val) 
            else:
                new_item(item, str(value))

        fill_item(self.invisibleRootItem(), value)

if __name__ == '__main__':
    app = QApplication([])
    window = ViewTree({ 'key1': 'value1', 'key3': [1,2,3, { 1: 3, 7 : 9}]})
    window.show()
    app.exec_()

Solution 3:

I found recursion makes it pretty slow while making a tree structure of a huge directory structure. The below method might help.

  def update_right_dock(self, file_list):   
            obj_list = []
            maps = []
            level = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]         #Stores Maximum and Current Levels For The TreeWidget
            level_name = ["", "", "", "", "", "", "", "", "", "", "", "", "", ""]   #Stores Previous File Path To Compare before adding file or folder to tree
            tree.clear()
            prev = ""
            tot_len = 2

            p = 0
            for file in file_list:
                if(os.path.isdir(file)):
                    is_file = 0
                else:
                    is_file = 1

                tmp_map = []

                file = file[1:]
                abs_path = file.split('/')
                abs_path_len = len(abs_path)
                filename = abs_path[-1]

                if(prev == file[:tot_len - 1]):
                    #print("LOOOOOOOOOOOOP ------ 1")
                    while (i < abs_path_len - 1):
                        level[level_counter + 1] = QTreeWidgetItem(level[level_counter], [abs_path[i]])

                        tmp_map.append(level[level_counter + 1])
                        tmp_map.append(level_counter + 1)
                        tmp_map.append(1)
                        obj_list.append(tmp_map)
                        tmp_map = []

                        level[level_counter + 1].setCheckState(0, Qt.Checked)
                        tree.expandItem(level[level_counter + 1])
                        level_counter = level_counter + 1
                        level_name[i] = abs_path[i]
                        i = i + 1
                    level[level_counter + 1] = QTreeWidgetItem(level[level_counter], [abs_path[i]])

                    tmp_map.append(level[level_counter + 1])
                    tmp_map.append(level_counter + 1)
                    tmp_map.append(0)
                    obj_list.append(tmp_map)
                    tmp_map = []

                    level[level_counter + 1].setCheckState(0, Qt.Checked)
                    tree.expandItem(level[level_counter + 1])

                    file_len = len(filename)
                    tot_len = len(file) - file_len
                    prev = file[:tot_len - 1]
                    continue


                len2 = len(level_name)
                k = 0
                while k < abs_path_len and k < len2:
                    if (level_name[k] == abs_path[k]):
                        k  = k + 1
                        continue
                    break
                level_counter = k + 1
                i = level_counter - 1
                while k < abs_path_len:
                    level_name[k] = abs_path[k]
                    k = k + 1

                if level_counter > 1:
                    #print("LOOOOOOOOOOOOP ------ 2")
                    if(i == abs_path_len - 1):
                        level_counter = level_counter - 1
                    while i < abs_path_len - 1:
                        level[level_counter] = QTreeWidgetItem(level[level_counter - 1], [abs_path[i]])

                        tmp_map.append(level[level_counter])
                        tmp_map.append(level_counter)
                        tmp_map.append(1)
                        obj_list.append(tmp_map)
                        tmp_map = []

                        level[level_counter].setCheckState(0, Qt.Checked)
                        tree.expandItem(level[level_counter])
                        level_counter = level_counter + 1
                        level_name[i] = abs_path[i]

                        i = i + 1
                        if i == abs_path_len - 1:
                                level_counter = level_counter - 1

                    level[level_counter + 1] = QTreeWidgetItem(level[level_counter], [abs_path[i]])

                    tmp_map.append(level[level_counter + 1])
                    tmp_map.append(level_counter + 1)
                    tmp_map.append(0)
                    obj_list.append(tmp_map)
                    tmp_map = []

                    level[level_counter + 1].setCheckState(0, Qt.Checked)
                    tree.expandItem(level[level_counter + 1])

                    file_len = len(filename)
                    tot_len = len(file) - file_len
                    prev = file[:tot_len - 1]
                    continue

                if(abs_path_len == 1):
                    level[level_counter + 1] = QTreeWidgetItem(tree, [abs_path[i]])

                    tmp_map.append(level[level_counter + 1])
                    tmp_map.append(level_counter + 1)
                    tmp_map.append(0)
                    obj_list.append(tmp_map)
                    tmp_map = []

                    level[level_counter + 1].setCheckState(0, Qt.Checked)
                    tree.expandItem(level[level_counter + 1])
                    continue

                i = 1    
                #print("LOOOOOOOOOOOOP ------ 3")
                level[level_counter] = QTreeWidgetItem(tree, [abs_path[0]])

                tmp_map.append(level[level_counter])
                tmp_map.append(level_counter)
                tmp_map.append(1)
                obj_list.append(tmp_map)
                tmp_map = []

                level[level_counter].setCheckState(0, Qt.Checked)
                tree.expandItem(level[level_counter])
                level_name[level_counter - 1] = abs_path[0]       

                while i < abs_path_len - 1:
                    level[level_counter + 1] = QTreeWidgetItem(level[level_counter], [abs_path[i]])
                    tmp_map.append(level[level_counter + 1])
                    tmp_map.append(level_counter + 1)
                    tmp_map.append(1)
                    obj_list.append(tmp_map)
                    tmp_map = []

                    level[level_counter + 1].setCheckState(0, Qt.Checked)
                    tree.expandItem(level[level_counter + 1])
                    level_counter = level_counter + 1
                    level_name[i] = abs_path[i]
                    if i == abs_path_len - 1:
                            level_counter = level_counter - 1
                    i = i + 1

                level[level_counter + 1] = QTreeWidgetItem(level[level_counter], [abs_path[i]])
                tmp_map.append(level[level_counter + 1])
                tmp_map.append(level_counter + 1)
                tmp_map.append(0)
                obj_list.append(tmp_map)
                tmp_map = []

                level[level_counter + 1].setCheckState(0, Qt.Checked)
                tree.expandItem(level[level_counter + 1])
                level_name[i] = abs_path[i]

                file_len = len(filename)
                tot_len = len(file) - file_len
                prev = file[:tot_len - 1]
                p = p + 1

Solution 4:

Few days ago i searched such theme, but all i could find - how to fill tree, but not how to extract it. So i write some. Maybe someone still find this useful. Thanks to the prev author, i used his code with some improvements. This will load your collection (it may be list or dict or tuple with many children)

defload_tree(self, d):
    self.fill_widget(self.tree, d)

deffill_widget(self, widget, value):
    widget.clear()
    self.fill_item(widget.invisibleRootItem(), value)

deffill_item(self, item, value):
    defnew_item(parent, text):
        child = QTreeWidgetItem([str(text)])
        if text notin ("[dict]", "[list]", "[tuple]"):
            child.setFlags(child.flags() | Qt.ItemIsEditable)
        parent.addChild(child)
        child.setExpanded(True)

        return child

    ifisinstance(value, dict):
        new_parent = new_item(item, f"[{value.__class__.__name__}]")
        for elem_k, elem_v in value.items():
            sub_parent = new_item(new_parent, elem_k)
            self.fill_item(sub_parent, elem_v)
    elifisinstance(value, (tuple, list)):
        new_parent = new_item(item, f"[{value.__class__.__name__}]")
        for val in value:
            self.fill_item(new_parent, val)
    else:
        new_item(item, f"{value}")

And extract code a little bit more.. complicated. If someone can make it more fancy - pls do.

defget_dict(self):
    result = Nonedefunpack(to_unpack, key, source=None):
        for child_index inrange(to_unpack.childCount()):
            child = to_unpack.child(child_index)
            child_text = child.text(0)
            try:
                child_text = float(child_text)
            except ValueError:
                try:
                    child_text = int(child_text)
                except ValueError:
                    passif source isNone:
                core = result
            else:
                core = source

            if key == "[dict]":
                core.update({child_text: None})
                if child.childCount() > 0:
                    unpack(child, child_text, core)
            elif key == "[list]"or key == "[tuple]":
                if child_text == "[dict]":
                    core.append({})
                elif child_text == "[list]"or child_text == "[tuple]":
                    core.append([])
                else:
                    core.append(child_text)

                if child.childCount() > 0:
                    unpack(child, child_text, core[child_index])
            else:
                if child_text == "[dict]":
                    core.update({key: {}})
                elif child_text == "[list]"or child_text == "[tuple]":
                    core.update({key: []})
                else:
                    core.update({key: child_text})

                if child.childCount() > 0:
                    unpack(child, child_text, core[key])

    for index inrange(self.tree.topLevelItemCount()):
        parent = self.tree.topLevelItem(index)
        element_text = parent.text(0)
        if element_text == "[dict]":
            result = {}
            unpack(parent, element_text)
        elif element_text == "[list]"or element_text == "[tuple]":
            result = []
            unpack(parent, element_text)
        else:
            result = element_text

    return result

Where self.tree - QTreeWidget object in your window.

Post a Comment for "Qtreewidget To Mirror Python Dictionary"