Treeview技术问题:如何修改含指定值的行中特定列的值?
问题解决:Treeview更新时提示Item Not Found
问题场景
使用Treeview维护客户端列表,列定义为("name", "status", "activity"),逻辑如下:
- 收到
NAME:开头的Socket消息:插入新行,将客户端名称填入Name列 - 收到
CLOSED:开头的Socket消息:更新对应客户端行的Status和Activity列
运行时出现错误:
_tkinter.TclError: Item :Maikz not found
问题根源及修复步骤
1. 字符串清理不彻底,导致IID不匹配
Socket接收的消息可能包含换行、空格等多余字符,导致插入的行IID(唯一标识)和后续更新时传入的IID不一致。
修复方法:处理消息时用strip()清理前后空白字符:
# 处理NAME消息 x = self.message.replace("NAME:", "").strip() # 处理CLOSED消息 x = self.message.replace("CLOSED:", "").strip()
2. 插入行时Values参数格式错误
Treeview的values参数需要对应列数量的元素(这里是3列),直接传单个字符串会被拆分为字符填充,导致数据混乱甚至IID异常。
修复方法:传入包含3个元素的元组作为初始值:
# 插入新行时,给三列都设置初始值 self.clientlist.insert("", cust.END, iid=x, values=(x, "Online", "Active"))
3. 非主线程操作GUI控件不安全
Tkinter要求所有GUI操作必须在主线程执行,Socket接收线程直接操作Treeview会引发异常或不可预期的问题。
修复方法:用after()方法将GUI操作调度到主线程:
# 插入行的操作改为: self.master2.after(0, lambda name=x: self.clientlist.insert( "", cust.END, iid=name, values=(name, "Online", "Active") )) # 更新行的操作改为: self.master2.after(0, lambda name=x: self.clientlist.set( name, "status", "Eyes are closed" )) self.master2.after(0, lambda name=x: self.clientlist.set( name, "activity", "Eyes are closed" ))
4. 列名大小写不一致
代码中定义的列是小写的status、activity,但更新时用了大写的Status、Activity,虽未直接引发本次错误,但会导致后续列更新失败。
修复方法:统一使用小写列名,保持和定义一致。
5. 缺失traceback导入
异常处理中使用了traceback.format_exc()但未导入模块,需在代码开头添加:
import traceback
修正后的关键代码片段
import tkinter as tk from tkinter import ttk as tick import socket from threading import Thread import traceback # 新增导入 class GUI2(cust.CTk): #second window, not the root def __init__(self, a, b, c, d, e): self.PORT = a self.SERVER = b self.ADDRESS = c self.FORMAT = d self.host = e self.master2 = cust.CTkToplevel() self.columns = ("name", "status", "activity") self.clientlist = tick.Treeview(self.clientframe, columns = self.columns, show = "tree") self.clientlist.grid(row = 0, column = 0, sticky = "nswe") self.clientlist.column("#0", minwidth = 0, width = 10, stretch = False) self.clientlist.column("name", minwidth = 0, width = 140, stretch = False) self.clientlist.column("status", minwidth = 0, width = 140, stretch = False) self.clientlist.column("activity", minwidth = 0, width = 140, stretch = False) self.thread = Thread(target = self.initreceiver) self.thread.start() def initreceiver(self): try: while True: self.message = self.host.recv(1024).decode(self.FORMAT) if "NAME:" in self.message: x = self.message.replace("NAME:", "").strip() # 主线程执行插入操作 self.master2.after(0, lambda name=x: self.clientlist.insert( "", cust.END, iid=name, values=(name, "Online", "Active") )) elif "CLOSED:" in self.message: x = self.message.replace("CLOSED:", "").strip() # 主线程执行更新操作 self.master2.after(0, lambda name=x: self.clientlist.set( name, "status", "Eyes are closed" )) self.master2.after(0, lambda name=x: self.clientlist.set( name, "activity", "Eyes are closed" )) except Exception: print(traceback.format_exc())
内容的提问来源于stack exchange,提问作者N. Tanaka
相关产品推荐
相关产品推荐

