2014-02-15 82 views
6

有沒有辦法使QTreeWidget鏡像對內部數據結構(如字典)所做的更改進行映射?看起來他們會在api中創建這個功能,因爲有很多程序可能與多個GUI區域中的QTreeWidget相互作用,但QTreeWidget要求的主要目的是在任何時間點顯示數據結構。 QtGui項目的文檔對我來說並不那麼簡單,因爲它通常是指C文檔,我不確定它是如何轉換爲python的。QTreeWidget鏡像python字典

所以基本上我最喜歡的是使QTreeWidget顯示嵌套字典的最簡單的方式,其中頂級對應於鍵,子級對應於值。此外,如果值是字典,請使用該級別中的鍵併爲值設置子級別等。

這很容易實現嗎?我一直無法找到任何東西來做這樣的簡單鏡像數據結構。

+1

[這](http://stackoverflow.com/questions/15178807/python-pyside-using-a-custom-widget-in-a-qtreewidget)問題看起來相似,但僅提供了一種通用方法,沒有可悲的代碼。但它可能會幫助你 – M4rtini

+0

雖然你可以用'QTreeWidget'來做到這一點,你真的應該使用由模型支持的'QTreeView'。否則,您將不斷需要重新填充整個樹來反映更改。 –

回答

15

這是一個簡單的實現:

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

結果:

screenshot

+0

這絕對是太棒了!非常感謝。每次調用一個按鈕來調用某個改變字典的函數時,這真是太棒了。我最終在每個調用改變數據結構的按鈕的函數調用中調用'treeWidget.clear()''fill_item'和'treeWidget.show()'之前。 – chase

+0

爲了方便,我在代碼中加了'fill_widget'函數。 –

1

只是因爲我最近需要這個實施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_() 
0

我發現遞歸m在製作巨大目錄結構的樹結構時,它的速度非常慢。下面的方法可能會有幫助。

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