Creating a Hierarchical Gtk.TreeStore with Unkown Dataset Length

69 Views Asked by At

All the examples I've seen of creating a hierarchical Gtk.Treestore use a file directory to populate the Store (see Create tree hierarchy using os.walk and gobject gtk+3). My data is the following:

['Power'],
['Power','Battery'],
['Power','PSU'],
['Power','Transformer'],
['Power','Transformer','Toroidal'],
['Power','Transformer','Toroidal','EI',],
['Power','Transformer','Toroidal','FI'],
['Resistor'],
['Resistor','Film'],
['Resistor','Metal'],
['Resistor','Potentiometer']
]

which would result in several levels of children.

This example from PyGObject : How could i get selected item in treeStore:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
class TreeStore(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.set_default_size(200, 200)
        self.connect("destroy", Gtk.main_quit)

# data known
        mylist = ["1","2","3","4","5"]

        scrolledwindow = Gtk.ScrolledWindow()
        scrolledwindow.set_hexpand(True)
        scrolledwindow.set_vexpand(True)
        self.add(scrolledwindow)
        treestore = Gtk.TreeStore(str)

# data known
        ListOne = treestore.append(None, ["List One"])
        ListTwo = treestore.append(None, ["List Two"])
        ListThree = treestore.append(None, ["List Three"])

        treeview = Gtk.TreeView()
        treeview.set_model(treestore)
        scrolledwindow.add(treeview)
        cellrenderertext = Gtk.CellRendererText()
        treeviewcolumn = Gtk.TreeViewColumn("Lists")
        treeview.append_column(treeviewcolumn)
        treeviewcolumn.pack_start(cellrenderertext, True)
        treeviewcolumn.add_attribute(cellrenderertext, "text", 0)
        for listItem in mylist:
            treestore.append(ListOne, [listItem])

# data known:
        treestore.append(ListTwo, ["foo"])
        treestore.append(ListTwo, ["Fido"])
        treestore.append(ListThree, ["Spot"])

window = TreeStore()
window.show_all()
Gtk.main()

does what I want, but as I've noted in the code the data are known. My data is generated from a database where the data are in a hierarchy and I've generated the data list from this:

ckey    ccategory   cparentkey
1       Library     0
2       Notes       0
3       Parts       0
16      Power       3
17      Battery     16
18      PSU         16
19      Resistor    3
20      Film        19
21      Metal       19
22      Potentiometer   19
50      Transformer 16
51      Toroidal    50
52      EI          51
53      FI          51

query and so I will not know what the data set will be. I've had several attempt over the last few months, but ended up using combobox instead. Can any one help me generate a treestore for my data. Thank you in advance.

2

There are 2 best solutions below

0
On

I finally figured out the solution for anybody who needs it in the future, thanks to Bryan Oakley, who helped me with a Tkinter solution at: Hierarchy in TKinter Treeview. Here's a working example:

# https://stackoverflow.com/questions/76427399/
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class app(Gtk.Window):
# /57036493/
    def add_node(self, rootNode, subNodes):
        for i, j in subNodes.items():
            self.rowCounter+=1
            self.store.insert(self.myiter, 1,(i,self.myList[self.rowCounter][1])) # /76427399/
            if isinstance(j, dict):
                self.add_node(i, j)
                
    def __init__(self):
        Gtk.Window.__init__(self)
        self.set_default_size(500,500)
        self.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]]
        
# Create Tree
        self.store = Gtk.TreeStore(str, int)

        self.mytreeview = Gtk.TreeView.new_with_model(self.store)
        for n, name in enumerate(['Category', 'Num']):
            cell = Gtk.CellRendererText()
            column = Gtk.TreeViewColumn(name, cell, text = n)
            if True:
                column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
                column.set_fixed_width(50)
                column.set_min_width(50)
                column.set_expand(True)
            column.set_resizable(True)
            column.set_reorderable(False)
            self.mytreeview.append_column(column)
        myscroll = Gtk.ScrolledWindow()
        myscroll.set_hexpand(True)
        myscroll.set_vexpand(True)
        myscroll.add(self.mytreeview)
        self.add(myscroll)
        
# Create a hierarchical dict - /59767830/, /52971687/
        hierarchy = {}
        for path in self.myList:
            node = hierarchy
            for level in path[0].split(' | '):
                if level:
                    node = node.setdefault(level, dict())

# Insert Nodes on the tree # /57036493/
        self.rowCounter=0
        for rootNode, subNodes in hierarchy.items():
            self.myiter = self.store.insert(None, 1, (rootNode,self.myList[self.rowCounter][1]))
            self.add_node(rootNode, subNodes)
            self.rowCounter+=1
        self.show_all()
p=app()
Gtk.main()
0
On

For PyQt5:

# /59767830/, /52971687/, /76427399/, /76410276/
from PyQt5.QtWidgets import (QApplication, QVBoxLayout, QMainWindow, QStackedWidget, QTreeWidget, QWidget, QTreeWidgetItem)
import sys
class App(QMainWindow):
    
    def build_tree(self, data=None, parent=None):
        for key, value in data.items():
            item = QTreeWidgetItem(parent)
            item.setText(0, key)
            item.setText(1, str(self.myList[self.rowCounter][1]))
            self.rowCounter+=1
            if isinstance(value, dict):
                self.build_tree(data=value, parent=item)

    def create_dict(self, mydata):
        tree = {}
        for path in mydata:
            node = tree
            for level in path[0].split(' | '):
                if level:
                    node = node.setdefault(level, dict())
        return tree

    def __init__(self):
         super().__init__()
         self.initUI()

    def initUI(self):
        self.rowCounter=0
        self.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]]
        mydict = self.create_dict(self.myList)
# Create Gui
        self.mainWidget = QWidget()
        self.layout = QVBoxLayout()
        self.mainWidget.setLayout(self.layout)
        self.setCentralWidget(self.mainWidget) # /13550076/
        treewidget = QTreeWidget()
        treewidget.setColumnCount(2) #/8961449/
        self.layout.addWidget(treewidget)
        self.show()
# Load the data
        self.build_tree(data=mydict, parent=treewidget)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())