Search code examples
pythontkintertreeview

Hierarchy in TKinter Treeview


I have been trying to create a Hierarchical TreeView with data from a database in Gtk but have been unsuccessful (Creating a Hierarchical Gtk.TreeStore with Unkown Dataset Length). I discovered that in TKinter I can almost do what I want, but there are a couple of problems.

  1. If a node has an identical value to another, Python throws up the following error:
    add_node(k, v, x)
  File "/home/bigbird/tvTk3.py", line 10, in add_node
    tree.insert(k, 1, i, text=i,values=[myList2[x][1]])
  File "/usr/lib/python3.10/tkinter/ttk.py", line 1361, in insert
    res = self.tk.call(self._w, "insert", parent, index,
_tkinter.TclError: Item Electric already exists

Is is possible to have nodes with the same name? And what do I change to avoid this?

  1. I want the number associated with each value to be inserted in column 1 of the treeview. But the line values=[myList[x][1]] does not change with each new node. How do I get the associated number in the row?

Could somebody help me get this going? Thank you very much.

import tkinter as tk
from tkinter import ttk as ttk

myList = [['Board', 71], ['Book', 8], ['Breadboard', 6], ['Cables', 48], ['Capacitor', 9], ['Capacitor | Ceramic', 10], ['Capacitor | Electrolytic', 11], ['Circuits', 73], ['Circuits | 555 Timer', 77], ['Circuits | Audio', 76], ['Connector', 12], ['Connectors', 49], ['Drill', 54], ['Drill | Electric', 56], ['Drill | Manual', 55], ['Screwdriver', 32], ['Screwdriver | Electric', 58], ['Screwdriver | Manual', 57], ['Veraboard', 7], ['Wire', 35], ['Wire | Jumper', 36], ['Wire | Solid Core', 37], ['Wire | Stranded', 38]]
# MyList2 replaces ['Screwdriver | Electric', 58], ['Screwdriver | Manual', 57], of MyList with ['Screwdriver | Electrical', 58], ['Screwdriver | Hand', 57],
myList2 = [['Board', 71], ['Book', 8], ['Breadboard', 6], ['Cables', 48], ['Capacitor', 9], ['Capacitor | Ceramic', 10], ['Capacitor | Electrolytic', 11], ['Circuits', 73], ['Circuits | 555 Timer', 77], ['Circuits | Audio', 76], ['Connector', 12], ['Connectors', 49], ['Drill', 54], ['Drill | Electric', 56], ['Drill | Manual', 55], ['Screwdriver', 32], ['Screwdriver | Electrical', 58], ['Screwdriver | Hand', 57], ['Veraboard', 7], ['Wire', 35], ['Wire | Jumper', 36], ['Wire | Solid Core', 37], ['Wire | Stranded', 38]]
# /57036493/
def add_node(k, v,x):
    for i, j in v.items():
        tree.insert(k, 1, i, text=i,values=[myList[x][1]]) # MyList2 will work, MyList does not
        if isinstance(j, dict):
            add_node(i, j,x)

# /59767830/, /52971687/
tree = {}
for path in myList: # MyList2 will work, MyList does not
    node = tree
    for level in path[0].split(' | '):
        if level:
            node = node.setdefault(level, dict())

# /57036493/
hierarchy = tree
root = tk.Tk()
root.geometry("900x900")
tree = ttk.Treeview(root)
ttk.Style().configure('Treeview', rowheight=30)
tree["columns"] = ("one")
tree.column("one")

x=0
for k, v in hierarchy.items():
    tree.insert("", 1, k, text=k, values=[myList[x][1]]) # MyList2 will work, MyList does not
    add_node(k, v, x)
    x+=1

tree.pack(expand=True, fill='both')
root.mainloop()

Solution

  • Is is possible to have nodes with the same name?

    I'm not sure what you mean by "name". Same text? Yes. Same id? No. Element identifiers must be unique. However, the id doesn't have to match the text that you see.

    And what do I change to avoid this?

    The simple solution is to let tkinter compute the id for each element. For example, just omit the third positional parameter:

    tree.insert(k, 1, text=i, values=[myList[x][1]])
    

    If you need the id, the insert method returns it.

    element_id = tree.insert(k, 1, text=i, values=[myList[x][1]])