Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi-level QTreeView

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.

like image 222
f.rodrigues Avatar asked Jan 12 '15 09:01

f.rodrigues


1 Answers

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':{}},
             ...
       }
like image 169
Avaris Avatar answered Sep 19 '22 21:09

Avaris