【问题标题】:QTreeWidget to Mirror python DictionaryQTreeWidget 镜像 python 字典
【发布时间】:2014-03-15 07:55:48
【问题描述】:

有没有办法让QTreeWidget 反映对字典等内部数据结构所做的更改?似乎他们会在 api 中创建此功能,因为有许多程序可以从多个 GUI 区域与 QTreeWidgets 交互,但 QTreeWidget 所需的主要目的是在任何时候显示数据结构及时。 QtGui items 的文档对我来说并不是那么容易掌握,因为它通常是指 C 文档,我不确定它是如何转移到 python 的。

所以基本上我想要的是让QTreeWidget 显示嵌套字典的最简单方法,其中顶层对应于键,子层对应于值。此外,如果值是字典,则使用该级别中的键并为值创建子级别等。

这很容易做到吗?我还没有找到任何东西来做像这样的数据结构的简单镜像。

【问题讨论】:

  • This questions 看起来很相似,但只提供了一个通用程序,遗憾的是没有代码可循。但它可能会帮助你
  • 虽然您可以使用QTreeWidget 来执行此操作,但您确实应该使用由模型支持的QTreeView。否则,您将不得不不断地重新填充整个树以反映更改。

标签: python qt pyqt qtreewidget


【解决方案1】:

这是一个简单的实现:

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)

我添加了列表支持以防万一有人需要。

用法:

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()

结果:

【讨论】:

  • 这真是太棒了!太感谢了。这对于每次使用按钮调用某些更改字典的函数时都进行调用非常棒。我最终在从更改数据结构的按钮调用的每个函数调用中调用了treeWidget.clear() 之前的fill_itemtreeWidget.show()
  • 为方便起见,我在代码中添加了fill_widget 函数。
【解决方案2】:

仅仅因为我最近需要 Python3 和 PyQt5 的这个实现,这里是给定示例的一个稍微短一些(并且完整)的端口:

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_()

【讨论】:

    【解决方案3】:

    我发现递归在制作巨大目录结构的树结构时会变得非常慢。下面的方法可能会有所帮助。

      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
    

    【讨论】:

      【解决方案4】:

      几天前我搜索了这样的主题,但我只能找到 - 如何填充树,而不是如何提取它。所以我写了一些。也许有人仍然觉得这很有用。 感谢上一个作者,我使用他的代码进行了一些改进。 这将加载您的集合(可能是列表或字典或具有许多孩子的元组)

      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}")
      

      并提取更多代码......复杂。如果有人可以让它更花哨 - 请这样做。

      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
      

      self.tree - 窗口中的 QTreeWidget 对象。

      【讨论】:

        猜你喜欢
        • 2014-07-09
        • 1970-01-01
        • 1970-01-01
        • 2019-03-15
        • 1970-01-01
        • 2021-12-15
        • 2021-07-16
        • 2013-10-21
        • 1970-01-01
        相关资源
        最近更新 更多