英文:
Hierarchy in TKinter Treeview
问题
我一直在尝试在Gtk中使用数据库中的数据创建一个层次结构的TreeView,但一直没有成功(https://stackoverflow.com/questions/76410276/creating-a-hierarchical-gtk-treestore-with-unkown-dataset-length)。我发现在Tkinter中几乎可以实现我想要的,但存在一些问题。
1)如果一个节点的名称与另一个节点相同,Python会引发以下错误:
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
是否可以有相同名称的节点?我应该如何更改以避免这个问题?
2)我希望与每个节点关联的数字被插入到TreeView的第1列中。但是,行的values=[myList[x][1]]在每个新节点中都没有改变。我如何获得与行关联的数字?
是否有人可以帮助我解决这个问题?非常感谢。
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=[myList2[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()
英文:
I have been trying to create a Hierarchical TreeView with data from a database in Gtk but have been unsuccessful (https://stackoverflow.com/questions/76410276/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.
- 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?
- I want the number associated with each value to be inserted in column 1 of the treeview. But the line values=[myList [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()
答案1
得分: 1
是的,可以拥有相同名称的节点。
我不确定你所指的“名称”是什么意思。相同的文本?是的。相同的标识符?不行。元素标识符必须是唯一的。但是,标识符不必与你看到的文本匹配。
要避免这种情况,简单的解决方案是让tkinter为每个元素计算标识符。例如,只需省略第三个位置参数:
tree.insert(k, 1, text=i, values=[myList[x][1]])
如果你需要标识符,insert
方法会返回它。
element_id = tree.insert(k, 1, text=i, values=[myList[x][1]])
英文:
> 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]])
答案2
得分: 0
我最终解决了我遇到的第二个问题(正如Brian所说,这是一个完全不同的问题)。正如下面的代码所示,正确跟踪当前行(称为self.rowCounter)是必要的。我已经整理了上面混乱的代码,使其更清晰,程序正在正确运行。
import tkinter as tk
from tkinter import ttk as ttk
class App:
def add_node(self, rootNode, subNodes):
for i, j in subNodes.items():
self.rowCounter += 1
self.tree.insert(rootNode, 1, text=i, values=[self.myList[self.rowCounter][1]])
if isinstance(j, dict):
self.add_node(i, j)
def __init__(self, root):
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]]
self.tree = ttk.Treeview(root)
self.tree["columns"] = ("one")
self.tree.pack(expand=True, fill='both')
hierarchy = {}
for path in self.myList:
node = hierarchy
for level in path[0].split(' | '):
if level:
node = node.setdefault(level, dict())
self.rowCounter = 0
for rootNode, subNodes in hierarchy.items():
self.tree.insert("", 1, rootNode, text=rootNode, values=[self.myList[self.rowCounter][1]])
self.add_node(rootNode, subNodes)
self.rowCounter += 1
root = tk.Tk()
app = App(root)
root.mainloop()
英文:
I finally figured out the second problem I had (as Brian said, a completely separate issue). As the code below shows, keeping track of the current row correctly (called self.rowCounter) was necessary. I have tidied up the above messy code so it is clearer and the program is running correctly.
import tkinter as tk
from tkinter import ttk as ttk
class App:
# /57036493/
def add_node(self, rootNode, subNodes):
for i, j in subNodes.items():
self.rowCounter+=1
self.tree.insert(rootNode, 1, text=i, values=[self.myList[self.rowCounter][1]]) # /76427399/
if isinstance(j, dict):
self.add_node(i, j)
def __init__(self, root):
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.tree = ttk.Treeview(root)
self.tree["columns"] = ("one")
self.tree.pack(expand=True, fill='both')
# 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.tree.insert("", 1, rootNode, text=rootNode, values=[self.myList[self.rowCounter][1]])
self.add_node(rootNode, subNodes)
self.rowCounter+=1
root = tk.Tk()
app = App(root)
root.mainloop()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论