You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tkinter Treeview选中项删除后同步更新JSON的问题

问题:Tkinter Treeview删除选中项无法同步更新JSON,且报IndexError错误

我用Tkinter的Treeview展示JSON文件内容,原删除函数只能删除Treeview里的条目,没法同步更新JSON。修改函数尝试读写JSON后,控制台抛出IndexError: 元组索引超出范围,JSON文件也没被修改。

原删除函数(仅删除Treeview项)

def borrar_select():
        borrar1 = json_tree.selection()[0]
        json_tree.delete(borrar1)

尝试修改后的函数

def borrar_select():
    with open('prueba1.json', "r") as f:
        data = json.load(f)

    for record in data['Clientes']:
        borrar1 = json_tree.selection()[0]
        json_tree.delete(borrar1)

    with open('prueba1.json', "w") as f:
        json.dump(record,f,indent=4)

#清空输入框
    logo_lb.delete(0,END) 
    name_lb.delete(0,END)
    lastname_lb.delete(0,END)
    something_lb.delete(0,END)

错误信息

PS C:\Users\*\Desktop\Tkinter> & E:/Prog/Python3/Python311/python.exe c:/Users/*/Desktop/Tkinter/test1.py
Tkinter回调异常
回溯(最近的调用最后):
  文件 "E:\Prog\Python3\Python311\Lib\tkinter\__init__.py", 第1948行, in __call__
    return self.func(*args)
           ^^^^^^^^^^^^^^^^
  文件 "c:\Users\*\Desktop\Tkinter\test1.py", 第102行, in borrar_select
    borrar1 = json_tree.selection()[0]
              ~~~~~~~~~~~~~~~~~~~~~^^^
IndexError: 元组索引超出范围

完整示例代码

import json
from tkinter import ttk
from tkinter import *
import tkinter as tk

ventana = tk.Tk()
ventana.title("Test")
ventana.geometry("1000x600")

frame1 = tk.Frame(ventana, bg="green", height=300, width=700)
frame1.grid(row=1, column=0)

frame2 = tk.Frame(ventana, bg="yellow", height=300, width=700)
frame2.grid(row=2, column=0)

frame_entry = tk.Frame(frame2) #输入框容器
frame_entry.pack(pady=20)
    
tree_frame = tk.Frame(frame1) #Treeview容器
tree_frame.pack(pady=20)

#Treeview样式设置
style = ttk.Style()
style.theme_use("clam")
style.configure("Treeview", background="#c7c7c7", foreground="black", rowheight=25,fieldbackground="#a1a1a1")
style.map("Treeview", background=[('selected','green')])

tree_scroll = Scrollbar(tree_frame) #Treeview滚动条容器
tree_scroll.pack(side=RIGHT, fill=Y)
#Treeview列表
json_tree = ttk.Treeview(tree_frame, yscrollcommand=tree_scroll.set)
json_tree.pack()

#配置滚动条
tree_scroll.config(command=json_tree.yview)

#定义列
json_tree['column'] = ("Logo", "Name", "Last Name", "Something")

#列格式设置
json_tree.column("#0", width=0, minwidth=0)#隐藏列
json_tree.column("Logo", anchor="w", width=120)
json_tree.column("Name", anchor="w", width=120)
json_tree.column("Last Name", anchor="w", width=120)
json_tree.column("Something", anchor="w", width=120)


#表头设置
json_tree.heading("#0", text="", anchor="w")#隐藏列表头
json_tree.heading("Logo", text="Logo", anchor="w")
json_tree.heading("Name", text="Name", anchor="w")
json_tree.heading("Last Name", text="Last Name", anchor="w")
json_tree.heading("Something", text="Something", anchor="w")


#行颜色设置
json_tree.tag_configure('par', background="#fff")
json_tree.tag_configure('inpar', background="#d6d6d6")
    
#读取JSON文件并加载到Treeview

with open('prueba1.json', "r") as f:
    data = json.load(f)

    count=0
    for record in data['Clientes']:
        if count % 2 ==0:
            json_tree.insert(parent='', index="end", iid=count, text="", values=(record['Logo'],record['Name'],record['Last Name'],record['Something']), tags=('par',))
        else:    
            json_tree.insert(parent='', index="end", iid=count, text="", values=(record['Logo'],record['Name'],record['Last Name'],record['Something']), tags=('inpar',))

        count+=1
   

#输入框
l1 = Label( frame_entry, text="Logo")
l1.grid(row=0, column=0)
logo_lb = Entry( frame_entry)
logo_lb.grid(row=1, column=0)

l2 = Label( frame_entry, text="Name")
l2.grid(row=0, column=1)
name_lb = Entry(frame_entry)
name_lb.grid(row=1, column=1)

l3 = Label( frame_entry, text="Last Name")
l3.grid(row=0, column=2)
lastname_lb = Entry(frame_entry)
lastname_lb.grid(row=1, column=2)

l4 = Label( frame_entry, text="Something")
l4.grid(row=0, column=3,)
something_lb = Entry(frame_entry)
something_lb.grid(row=1, column=3)

#按钮函数
def borrar_select():
    with open('prueba1.json', "r") as f:
        data = json.load(f)

    for record in data['Clientes']:
        borrar1 = json_tree.selection()[0]
        json_tree.delete(borrar1)

    with open('prueba1.json', "w") as f:
        json.dump(record,f,indent=4)

#清空输入框
    logo_lb.delete(0,END) 
    name_lb.delete(0,END)
    lastname_lb.delete(0,END)
    something_lb.delete(0,END)
            
borrar_btn = tk.Button(frame2, text="Delete", command=borrar_select)
borrar_btn.pack(side=RIGHT, ipadx=30, pady=10)

def select_record():
    #清空输入框
    logo_lb.delete(0,END) 
    name_lb.delete(0,END)
    lastname_lb.delete(0,END)
    something_lb.delete(0,END)

    selected = json_tree.focus() #获取选中项的位置
    values = json_tree.item(selected,'values') #获取选中项的值

    logo_lb.insert(0, values[0]) 
    name_lb.insert(0,values[1])
    lastname_lb.insert(0,values[2])
    something_lb.insert(0,values[3])

        
select_btn = tk.Button(frame2, text="Select", command=select_record)
select_btn.pack(side=LEFT, ipadx=30,)

ventana.mainloop()

示例JSON内容

{
  "Clientes": [
    {
      "Logo": "C:/Users/*/Desktop/Tkinter/logos/selavalacarita.png",
      "Name": "2",
      "Last Name": "3",
      "Something": "4"
    },
    {
      "Logo": "C:/Users/*/Desktop/Tkinter/logos/selavalacarita.png",
      "Name": "1",
      "Last Name": "4",
      "Something": "7"
    }
  ]
}

错误原因分析

  1. IndexError触发原因:修改后的函数在for record in data['Clientes']循环内反复调用json_tree.selection()[0],第一次删除Treeview条目后,选中状态消失,后续循环再取选中项就会因无数据抛出索引越界错误。
  2. JSON未更新问题:循环结束后仅将最后一个record写入JSON,完全没处理删除逻辑,等于未修改原数据结构。
  3. Treeview的iid与JSON索引不匹配:加载数据时用count作为iid,但删除后Treeview的iid和JSON数组的索引对应关系断裂,无法直接通过iid定位JSON条目。

修正后的删除函数

核心逻辑:先获取选中项内容,匹配并删除JSON中对应条目,再清空Treeview重新加载更新后的JSON数据,同时增加空选判断避免报错。

def borrar_select():
    # 判断是否有选中项
    selected_items = json_tree.selection()
    if not selected_items:
        return
    
    # 获取选中项的内容
    selected_item = selected_items[0]
    item_values = json_tree.item(selected_item, 'values')
    
    # 读取JSON数据
    with open('prueba1.json', "r") as f:
        data = json.load(f)
    
    # 找到并删除JSON中对应的条目
    clientes = data['Clientes']
    for idx, record in enumerate(clientes):
        if (record['Logo'] == item_values[0] and
            record['Name'] == item_values[1] and
            record['Last Name'] == item_values[2] and
            record['Something'] == item_values[3]):
            del clientes[idx]
            break
    
    # 将更新后的数据写入JSON
    with open('prueba1.json', "w") as f:
        json.dump(data, f, indent=4)
    
    # 清空Treeview并重新加载数据
    for item in json_tree.get_children():
        json_tree.delete(item)
    
    count = 0
    for record in data['Clientes']:
        if count % 2 == 0:
            json_tree.insert(parent='', index="end", iid=count, text="", 
                            values=(record['Logo'], record['Name'], record['Last Name'], record['Something']), 
                            tags=('par',))
        else:
            json_tree.insert(parent='', index="end", iid=count, text="", 
                            values=(record['Logo'], record['Name'], record['Last Name'], record['Something']), 
                            tags=('inpar',))
        count += 1
    
    # 清空输入框
    logo_lb.delete(0, END) 
    name_lb.delete(0, END)
    lastname_lb.delete(0, END)
    something_lb.delete(0, END)

替换原代码中的borrar_select函数即可解决问题。

额外优化建议

  • 如果JSON条目有唯一标识(如ID字段),用唯一标识匹配会比全字段匹配更可靠
  • 可添加弹窗提示,告知用户删除成功或未选中任何条目

内容的提问来源于stack exchange,提问作者Avada Kedavra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 14:40:17