Python 手动更改treeview中的值和列名

Python 手动更改treeview中的值和列名,python,tkinter,Python,Tkinter,在treeview中,是否有任何方法可以通过单击要编辑的单元格来更改/删除/更新或添加新值? 这个问题对于列名也是一样的,我可以通过单击并在列名上书写来手动更改列名吗 这是我写的treeview代码: from tkinter import * from tkinter import ttk myApp = Tk() myApp.title("tree") myApp.geometry("300x400") tree = ttk.Treevi

在treeview中,是否有任何方法可以通过单击要编辑的单元格来更改/删除/更新或添加新值? 这个问题对于列名也是一样的,我可以通过单击并在列名上书写来手动更改列名吗

这是我写的treeview代码:

from tkinter import *
from tkinter import ttk

myApp = Tk()
myApp.title("tree")                         
myApp.geometry("300x400")

tree = ttk.Treeview(myApp)
tree['show'] = 'headings'

sb = ttk.Scrollbar(myApp, orient="vertical", command=tree.yview)
sb.grid(row=1,column=12,rowspan=12,sticky="NS")

tree.configure(yscrollcommand=sb.set)

tree["columns"]=("1")

tree.column("1", width=230)
tree.heading("1", text="Name")

tree.insert("","end", values=("item"))

tree.grid(row=1 ,column=0,pady=5)

myApp.mainloop()

您想要实现的目标是可能的,但是您不能直接在
树状视图
单元格中写入文本,因此技巧是使用
放置
在您想要编辑的单元格顶部显示一个
条目

因此,我们的想法如下:

  • Treeview
    中的鼠标单击绑定到
    edit
    功能
  • 在此函数中,使用
    tree.identification_region(x,y)
    确定单击在
    Treeview
    树的哪个部分。
    • 如果这是一个单元格,您可以使用
      树获取项目名称。标识行(y)
      和列(x),然后使用
      树.bbox(项目,列)
      函数获取
      条目的位置和尺寸
    • 如果这是一个标题,则会有点复杂,因为
      bbox
      仅适用于项目。我们仍然可以使用
      bbox
      获得列的x和宽度,但不能获得y和高度。因此,我们的想法是增加y,直到我们使用
      树找到标题的边界。识别_区域(x,y)
      以检查我们是否仍在标题内(见下面的代码)
    • 如果为“nothing”,并且您位于最后一个项目下方,则可以在最后一个项目下方显示
      条目
  • 条目
    放在要编辑的元素顶部
  • 当用户点击
    时编辑元素文本并销毁
    条目
代码如下:

import tkinter as tk
from tkinter import ttk


def edit(event):

    if tree.identify_region(event.x, event.y) == 'cell':
        # the user clicked on a cell

        def ok(event):
            """Change item value."""
            tree.set(item, column, entry.get())
            entry.destroy()

        column = tree.identify_column(event.x)  # identify column
        item = tree.identify_row(event.y)  # identify item
        x, y, width, height = tree.bbox(item, column) 
        value = tree.set(item, column)

    elif tree.identify_region(event.x, event.y) == 'heading': 
        # the user clicked on a heading

        def ok(event):
            """Change heading text."""
            tree.heading(column, text=entry.get())
            entry.destroy()

        column = tree.identify_column(event.x) # identify column
        # tree.bbox work sonly with items so we have to get the bbox of the heading differently
        x, y, width, _ = tree.bbox(tree.get_children('')[0], column) # get x and width (same as the one of any cell in the column)
        # get vertical coordinates (y1, y2)
        y2 = y
        # get bottom coordinate
        while tree.identify_region(event.x, y2) != 'heading':  
            y2 -= 1
        # get top coordinate
        y1 = y2
        while tree.identify_region(event.x, y1) == 'heading':
            y1 -= 1
        height = y2 - y1
        y = y1
        value = tree.heading(column, 'text')

    elif tree.identify_region(event.x, event.y) == 'nothing': 
        column = tree.identify_column(event.x) # identify column
        # check whether we are below the last row:
        x, y, width, height = tree.bbox(tree.get_children('')[-1], column)
        if event.y > y:

            def ok(event):
                """Change item value."""
                # create item
                item = tree.insert("", "end", values=("", ""))
                tree.set(item, column, entry.get())
                entry.destroy()

            y += height
            value = ""
        else:
            return
    else:
        return
    # display the Entry   
    entry = ttk.Entry(tree)  # create edition entry
    entry.place(x=x, y=y, width=width, height=height,
                anchor='nw')  # display entry on top of cell
    entry.insert(0, value)  # put former value in entry
    entry.bind('<FocusOut>', lambda e: entry.destroy())  
    entry.bind('<Return>', ok)  # validate with Enter
    entry.focus_set()


myApp = tk.Tk()

tree = ttk.Treeview(myApp, show='headings', columns=("1", "2"))
tree['show'] = 'headings'

tree.column("1", width=230)
tree.heading("1", text="Name")
tree.column("2", width=230)
tree.heading("2", text="Price")
for i in range(10):
    item = tree.insert("", "end", values=("item %i" % i, i))
    tree.item(item, tags=item)
tree.bind('<1>', edit)

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

myApp.mainloop()
将tkinter作为tk导入
从tkinter导入ttk
def编辑(事件):
if tree.identification_区域(event.x,event.y)=‘cell’:
#用户单击了一个单元格
def ok(事件):
“”“更改项目值。”“”
tree.set(item、column、entry.get())
entry.destroy()
column=tree.identify_column(event.x)#identify column
项目=树。标识_行(event.y)#标识项目
x、 y,宽度,高度=tree.bbox(项目,列)
value=tree.set(项、列)
elif树。标识_区域(event.x,event.y)=‘heading’:
#用户单击了一个标题
def ok(事件):
“”“更改标题文本。”“”
tree.heading(列,text=entry.get())
entry.destroy()
column=tree.identify_column(event.x)#identify column
#tree.bbox仅适用于项目,因此我们必须以不同的方式获取标题的bbox
x、 y,width,=tree.bbox(tree.get_children(“”)[0],column)#get x和width(与列中任何单元格的值相同)
#获取垂直坐标(y1,y2)
y2=y
#获取底部坐标
while tree.标识_区域(event.x,y2)!='标题':
y2-=1
#获取最高坐标
y1=y2
while tree.identification_region(event.x,y1)=“heading”:
y1-=1
高度=y2-y1
y=y1
value=tree.heading(列“text”)
elif树。标识_区域(event.x,event.y)=‘无’:
column=tree.identify_column(event.x)#identify column
#检查我们是否低于最后一行:
x、 y,宽度,高度=tree.bbox(tree.get_children(“”)[-1],列)
如果event.y>y:
def ok(事件):
“”“更改项目值。”“”
#创建项目
项=树。插入(“,”结束“),值=(“”,“”)
tree.set(item、column、entry.get())
entry.destroy()
y+=高度
value=“”
其他:
返回
其他:
返回
#显示条目
entry=ttk.entry(树)#创建版本条目
入口位置(x=x,y=y,宽度=宽度,高度=高度,
anchor='nw')#在单元格顶部显示条目
条目。插入(0,值)#将前一个值放入条目
entry.bind(“”,lambda e:entry.destroy())
entry.bind(“”,ok)#用Enter验证
entry.focus_set()
myApp=tk.tk()
tree=ttk.Treeview(myApp,show='headers',columns=(“1”,“2”))
树['show']='headers'
树.列(“1”,宽度=230)
树标题(“1”,text=“Name”)
树.列(“2”,宽度=230)
树标题(“2”,text=“Price”)
对于范围(10)内的i:
项=树。插入(“,”结束“,值=(“项%i”%i,i))
tree.item(item,tags=item)
tree.bind(“”,编辑)
tree.pack(fill='both',expand=True)
myApp.mainloop()

谢谢,但我可以用同样的方法添加新行吗?@AleksandarBeat要添加新项目,原则是一样的。我已经在我的功能中添加了这个案例。非常感谢,你真的帮助了我!还有一个问题,有没有办法在树状视图中放置网格?@AleksandarBeat我不明白你所说的“在树状视图中放置网格”是什么意思,你能解释一下吗?在列和行之间有行吗