Home > Software design >  Trying to recursively populate a ttk.treeview with json/dictionary in python
Trying to recursively populate a ttk.treeview with json/dictionary in python

Time:03-14

I am new to python, but have java experience. Pretty different animals. I have a method that creates a json/dictionary based on walking through a directory structure and I have it where it creates a json like the one below. I am trying to get another method to populate a treeview based on it. I have seen several examples here on stackoverflow and have attempted to follow them. Below is what I have come up with, but it always errs out after going through the first directory, like it lost track of where it was. the following errors are returned:

Traceback (most recent call last):
  File "temp.py", line 147, in <module>
    load_treeview_from_project_dictionary(myData, tree_view)
  File "temp.py", line 134, in load_treeview_from_project_dictionary
    load_treeview_from_project_dictionary(c, tree_view, int(c['index']))
  File "temp.py", line 136, in load_treeview_from_project_dictionary
    tree_view.insert(parent_id, "end", text=c['name'], values=("", ""))
  File "C:\Users\...\AppData\Local\Programs\Python\Python39\lib\tkinter\ttk.py", line 1364, in insert
    res = self.tk.call(self._w, "insert", parent, index, *opts)
_tkinter.TclError: Item 1 not found

I worked several hours trying to refactor and figure this out, but have been unsuccessful. I am now reaching out to this great community to point out the error of my ways! Please help.

import json
import tkinter
from tkinter import ttk
from tkinter.ttk import Label


myData = {
    "name": "MyRoot",
    "type": "directory",
    "index": 0,
    "children": [
        {
            "name": "SubDir1",
            "type": "directory",
            "index": 1,
            "children": [
                {
                    "name": "apic.png",
                    "type": "file"
                }
            ]
        },
        {
            "name": "SubDir2",
            "type": "directory",
            "index": 2,
            "children": [
                {
                    "name": "somefile.txt",
                    "type": "file"
                },
                {
                    "name": "anotherfile.txt",
                    "type": "file"
                }
            ]
        },
        {
            "name": "SubDir3",
            "type": "directory",
            "index": 3,
            "children": []
        },
        {
            "name": "SubDir4",
            "type": "directory",
            "index": 4,
            "children": [
                {
                    "name": "asomefile.txt",
                    "type": "file"
                },
                {
                    "name": "bsomefile.txt",
                    "type": "file"
                },
                {
                    "name": "csomefile.txt",
                    "type": "file"
                },
                {
                    "name": "dsomefile.txt",
                    "type": "file"
                },
                {
                    "name": "esomefile.txt",
                    "type": "file"
                }
            ]
        },
        {
            "name": "SubDir5",
            "type": "directory",
            "index": 5,
            "children": [
                {
                    "name": "NesterDir1",
                    "type": "directory",
                    "index": 6,
                    "children": []
                }
            ]
        },
        {
            "name": "SubDir6",
            "type": "directory",
            "index": 7,
            "children": []
        },
        {
            "name": "SubDir7",
            "type": "directory",
            "index": 8,
            "children": []
        },
        {
            "name": "SubDir8",
            "type": "directory",
            "index": 9,
            "children": []
        },
        {
            "name": "SubDir9",
            "type": "directory",
            "index": 10,
            "children": []
        },
        {
            "name": "SubDir10",
            "type": "directory",
            "index": 11,
            "children": []
        },
        {
            "name": "SubDir11",
            "type": "directory",
            "index": 12,
            "children": []
        }
    ]
}


def load_treeview_from_project_dictionary(data, my_tree_view, parent_id=None):
    print("this:"   data['name']   " called function!")
    if parent_id is None:
        my_tree_view.insert("", "0", text=data['name'], values=("", ""))  # applies to first iteration only
    if data['children'] is not None:
        for c in data['children']:
            print("child: "   c['name'])
            if c['type'] == "directory":
                my_tree_view.insert('', int(c['index']), text=c['name'], values=("", ""))
                load_treeview_from_project_dictionary(c, my_tree_view, int(c['index']))
            else:
                my_tree_view.insert(parent_id, "end", text=c['name'], values=("", ""))
                load_treeview_from_project_dictionary(c, my_tree_view, parent_id)


root = tkinter.Tk()

main_label = Label(root, text="Directory Tree")
tree_view = ttk.Treeview(root, height=23)

tree_view.heading("#0", text="Directory Structure")

load_treeview_from_project_dictionary(myData, tree_view)

main_label.pack()
tree_view.pack()

root.mainloop()

Thanks in Advance!

CodePudding user response:

So. After reviewing the tutorial link posted by D.L and then combing through my code and debugging over and over, I came to the conclusion that there was too much recursion going on. Watching the flow I found that the method always stopped after the first file was added to the tree. Taking the recursive call after the file insert fixed a large part of the issue. I scrutinized the insertion process and found that I could use the indices in the json for the treeview's iid's. I then decided that it would be more efficient to use the treeview.move to place the entries where I wanted them as they are being inserted. Below is what I came up with and it works great. I am posting this here for anyone else that runs into the same issue. After the code, there is a screenshot of the resulting treeview (or a link to it due to my rank- I will try to fix that later)

import json
import tkinter
from tkinter import ttk
from tkinter.ttk import Label

myData = {
    "name": "MyRoot",
    "type": "directory",
    "index": 0,
    "children": [
        {
            "name": "SubDir1",
            "type": "directory",
            "index": 1,
            "children": [
                {
                    "name": "apic.png",
                    "type": "file"
                }
            ]
        },
        {
            "name": "SubDir2",
            "type": "directory",
            "index": 2,
            "children": [
                {
                    "name": "somefile.txt",
                    "type": "file"
                },
                {
                    "name": "anotherfile.txt",
                    "type": "file"
                }
            ]
        },
        {
            "name": "SubDir3",
            "type": "directory",
            "index": 3,
            "children": []
        },
        {
            "name": "SubDir4",
            "type": "directory",
            "index": 4,
            "children": [
                {
                    "name": "asomefile.txt",
                    "type": "file"
                },
                {
                    "name": "bsomefile.txt",
                    "type": "file"
                },
                {
                    "name": "csomefile.txt",
                    "type": "file"
                },
                {
                    "name": "dsomefile.txt",
                    "type": "file"
                },
                {
                    "name": "esomefile.txt",
                    "type": "file"
                }
            ]
        },
        {
            "name": "SubDir5",
            "type": "directory",
            "index": 5,
            "children": [
                {
                    "name": "NestedDir1",
                    "type": "directory",
                    "index": 6,
                    "children": [
                        {
                            "name": "yetAnotherfile.txt",
                            "type": "file"
                        }
                    ]
                }
            ]
        },
        {
            "name": "SubDir6",
            "type": "directory",
            "index": 7,
            "children": []
        },
        {
            "name": "SubDir7",
            "type": "directory",
            "index": 8,
            "children": []
        },
        {
            "name": "SubDir8",
            "type": "directory",
            "index": 9,
            "children": []
        },
        {
            "name": "SubDir9",
            "type": "directory",
            "index": 10,
            "children": []
        },
        {
            "name": "SubDir10",
            "type": "directory",
            "index": 11,
            "children": []
        },
        {
            "name": "SubDir11",
            "type": "directory",
            "index": 12,
            "children": []
        }
    ]
}


def load_treeview_from_project_dictionary(data, my_tree_view, parent_id=None):
    print('this:'   data['name']   ' called function!')
    if parent_id is None:
        my_tree_view.insert('', '0', text=data['name'], iid=0)  # applies to first iteration only
    for c in data['children']:
        print('child: '   c['name'])
        if c['type'] == 'directory':
            my_tree_view.insert('', 'end', text=c['name'], iid=c['index'])
            my_tree_view.move(c['index'], data['index'], 'end')
            load_treeview_from_project_dictionary(c, my_tree_view, data['index'])
        else:
            file_index = my_tree_view.insert('', 'end', text=c['name'])
            my_tree_view.move(file_index, data['index'], 'end')


root = tkinter.Tk()

main_label = Label(root, text='Directory Tree')
tree_view = ttk.Treeview(root, height=23)

tree_view.heading('#0', text='Directory Structure')

load_treeview_from_project_dictionary(myData, tree_view)

main_label.pack()
tree_view.pack()

root.mainloop()

Treeview screenshot

  • Related