2014-02-15 8 views
6

Gibt es eine Möglichkeit, eine QTreeWidget Spiegelung der Änderungen an einer internen Datenstruktur wie Wörterbuch machen? Es scheint, als hätten sie diese Funktionalität innerhalb der API erstellt, da es viele Programme gibt, die mit QTreeWidget s aus mehreren GUI-Bereichen interagieren können, aber der Hauptzweck des QTreeWidget ist es, eine Datenstruktur zu jedem Zeitpunkt anzuzeigen. Die Dokumentation für QtGui Elemente ist nicht so einfach für mich zu verstehen, da es normalerweise auf C-Dokumentation verweist, und ich bin nicht sicher, wie es auf Python überträgt.QTreeWidget zum Spiegeln python Wörterbuch

Also im Wesentlichen, was ich möchte, ist die einfachste Art und Weise zu einem QTreeWidget zeigen ein verschachteltes Wörterbuch, wobei die oberste Ebene entspricht den Schlüsseln entspricht und die Unterebene entspricht den Werten. Wenn es sich bei den Werten um Wörterbücher handelt, verwenden Sie die Tasten in dieser Ebene, und stellen Sie Unterebenen für die Werte usw. ein.

Ist das leicht machbar? Ich habe noch nichts gefunden, um Datenstrukturen so einfach zu spiegeln.

+1

[Dies] (http://stackoverflow.com/questions/15178807/python-pyside-using-a-custom-widget-in-a-qtreewidget) Fragen sehen ähnlich aus, aber sofern nur ein allgemeines Verfahren leider kein Code, dem man folgen sollte. Aber es könnte Ihnen helfen – M4rtini

+0

Während Sie dies mit einem 'QTreeWidget' tun können, sollten Sie wirklich ein' QTreeView' verwenden, das von einem Modell unterstützt wird. Andernfalls müssen Sie den gesamten Baum ständig aktualisieren, um Änderungen zu berücksichtigen. –

Antwort

15

Dies ist eine einfache Implementierung:

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 Liste Unterstützung hinzugefügt nur falls jemand es braucht.

Verbrauch:

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

Ergebnis:

screenshot

+0

Das ist absolut großartig! Ich danke dir sehr. Dies ist großartig, um jedes Mal anzurufen, wenn eine Taste verwendet wird, um eine Funktion aufzurufen, die das Wörterbuch verändert. Ich habe dann 'threeWidget.clear()' vor 'fill_item' und' treeWidget.show() 'in jedem Funktionsaufruf von Schaltflächen aufgerufen, die die Datenstruktur ändern. – chase

+0

Ich habe 'fill_widget' Funktion in meinem Code für die Bequemlichkeit hinzugefügt. –

1

Nur weil ich vor kurzem diese Implementierung benötigt für Python3 und PyQt5 hier ist ein wenig kürzer (und vollständige) -Anschluss des gegebenen Beispiel:

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

Ich fand Rekursion m Es ist ziemlich langsam, während man eine Baumstruktur mit einer riesigen Verzeichnisstruktur erstellt. Die folgende Methode könnte helfen.

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