QTreeWidget to Mirror python Dictionary

前端 未结 4 1446
北恋
北恋 2020-12-28 22:30

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 funct

相关标签:
4条回答
  • 2020-12-28 23:01

    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
    
    0 讨论(0)
  • 2020-12-28 23:02

    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

    0 讨论(0)
  • 2020-12-28 23:05

    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
    
    class ViewTree(QTreeWidget):
        def __init__(self, value):
            super().__init__()
            def fill_item(item, value):
                def new_item(parent, text, val=None):
                    child = QTreeWidgetItem([text])
                    fill_item(child, val)
                    parent.addChild(child)
                    child.setExpanded(True)
                if value is None: return
                elif isinstance(value, dict):
                    for key, val in sorted(value.items()):
                        new_item(item, str(key), val)
                elif isinstance(value, (list, tuple)):
                    for val in value:
                        text = (str(val) if not isinstance(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_()
    
    0 讨论(0)
  • 2020-12-28 23:05

    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)

    def load_tree(self, d):
        self.fill_widget(self.tree, d)
    
    def fill_widget(self, widget, value):
        widget.clear()
        self.fill_item(widget.invisibleRootItem(), value)
    
    def fill_item(self, item, value):
        def new_item(parent, text):
            child = QTreeWidgetItem([str(text)])
            if text not in ("[dict]", "[list]", "[tuple]"):
                child.setFlags(child.flags() | Qt.ItemIsEditable)
            parent.addChild(child)
            child.setExpanded(True)
    
            return child
    
        if isinstance(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)
        elif isinstance(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.

    def get_dict(self):
        result = None
    
        def unpack(to_unpack, key, source=None):
            for child_index in range(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:
                        pass
    
                if source is None:
                    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 in range(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.

    0 讨论(0)
提交回复
热议问题