5

I'm having a hard time understanding how to set a multilevel QTree using the QTreeView and QStandardItemModel.

Here's what I have:

from PySide.QtGui import *
import sys

class MainFrame(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        tree = {'root': {
                    "1": ["A", "B", "C"],
                    "2": {
                        "2-1": ["G", "H", "I"],
                        "2-2": ["J", "K", "L"]},
                    "3": ["D", "E", "F"]}
        }

        self.tree = QTreeView(self)
        root_model = QStandardItemModel()
        self.tree.setModel(root_model)

        for r,root in enumerate(sorted(tree)):
            root_item = QStandardItem(root)
            root_model.setItem(r,root_item)

            for c,child in enumerate(sorted(tree[root])):
                child_model = QStandardItemModel(root_model)
                child_item = QStandardItem(child)
                child_model.setItem(c, child_item)

                for gc, grand_child in enumerate(sorted(tree[root][child])):
                    grand_child_model = QStandardItemModel(child_model)
                    grand_child_item = QStandardItem(grand_child)
                    grand_child_model.setItem(gc,grand_child_item)

                    if type(tree[root][child]) == dict:
                        for ggc, gran_grand_child in enumerate(sorted(tree[root][child][grand_child])):
                            gran_grand_child_model = QStandardItemModel(grand_child_model)
                            gran_grand_child_item = QStandardItem(gran_grand_child)
                            gran_grand_child_model.setItem(ggc, gran_grand_child_item)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = MainFrame()
    main.show()
    sys.exit(app.exec_())

I want it to look like this:

tree

So far only the 'root' item is showing, it's not throwing any error.

Also, I made this for-loops in a bit of hurry, it's kind hard to read/understand because it has too many nested for loops. I wonder if there's a better way to expand the tree based on the initial dict.

f.rodrigues
  • 3,499
  • 6
  • 26
  • 62

1 Answers1

10

You're creating a model for each item. That's wrong. You should use .appendRow/.insertRow on an item to add child items.

As for your loops, I'd probably use a recursive method to populate the tree. Here is what I'd do:

from PySide.QtGui import *
import sys
import types

class MainFrame(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        tree = {'root': {
                    "1": ["A", "B", "C"],
                    "2": {
                        "2-1": ["G", "H", "I"],
                        "2-2": ["J", "K", "L"]},
                    "3": ["D", "E", "F"]}
        }

        self.tree = QTreeView(self)
        layout = QHBoxLayout(self)
        layout.addWidget(self.tree)

        root_model = QStandardItemModel()
        self.tree.setModel(root_model)
        self._populateTree(tree, root_model.invisibleRootItem())

    def _populateTree(self, children, parent):
        for child in sorted(children):
            child_item = QStandardItem(child)
            parent.appendRow(child_item)
            if isinstance(children, types.DictType):
                self._populateTree(children[child], child_item)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = MainFrame()
    main.show()
    sys.exit(app.exec_())

PS: You're also not using any layouts for the main window. I added it above.

PSv2: Type-checking is best avoided in python, if possible, but it's kind of necessary the way you structured your tree. It'd be better if you structured it differently, like dicts all the way maybe:

tree = {'root': {
            '1': {'A':{}, 'B':{}, 'C':{}},
             ...
       }
Avaris
  • 35,883
  • 7
  • 81
  • 72
  • Great, nice touch on the recursion, never would thought of that. – f.rodrigues Jan 13 '15 at 05:34
  • Your recursive loop as an inadequate stop rule, as "children" is always being iterated (will create a child for each char in a string for example) – Daniel Braun Nov 11 '18 at 09:50
  • @DanielBraun only if you do `{'foo': 'bar'}` instead of `{'foo': ['bar']}`. Anyway, this was meant as a pseudocode, more than an actual implementation. I can't write tree traversal if I don't know the tree structure. – Avaris Nov 11 '18 at 13:15