Tkinter Treeview第一列排序功能失效问题求助
Treeview 第一列(#0)排序报错:Display column #0 cannot be set
我参考教程实现Treeview列排序功能,第二、第三列可正常排序,但第一列点击表头时触发以下错误:
Exception in Tkinter callback Traceback (most recent call last): File "C:\Python311\Lib\tkinter\__init__.py", line 1967, in __call__ return self.func(*args) ^^^^^^^^^^^^^^^^ File "D:\...\Test_Treeview_book.py", line 20, in <lambda> tv.heading('#0', text='Name', command=lambda: sort(tv, '#0')) ^^^^^^^^^^^^^^ File "D:\...\Test_Treeview_book.py", line 14, in sort itemlist.sort(key=lambda x: tv.set(x, col)) File "D:\...\Test_Treeview_book.py", line 14, in <lambda> itemlist.sort(key=lambda x: tv.set(x, col)) ^^^^^^^^^^^^^^ File "C:\Python311\Lib\tkinter\ttk.py", line 1434, in set res = self.tk.call(self._w, "set", item, column, value) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _tkinter.TclError: Display column #0 cannot be set
测试代码如下:
import tkinter as tk from tkinter import ttk from pathlib import Path root = tk.Tk() root.grid_rowconfigure(0, weight=1) root.grid_columnconfigure(0, weight=1) paths = Path('.').glob('**/*') def sort(tv, col): # Doesn't work on 1st column '#0' itemlist = list(tv.get_children('')) itemlist.sort(key=lambda x: tv.set(x, col)) for index, iid in enumerate(itemlist): tv.move(iid, tv.parent(iid), index) tv = ttk.Treeview(root, columns=['size','modified'], selectmode=None) tv.heading('#0', text='Name', command=lambda: sort(tv, '#0')) tv.heading('size', text='Size', anchor='center', command=lambda: sort(tv, 'size')) tv.heading('modified', text='Modifies', anchor='center', command=lambda: sort(tv, 'modified')) tv.column('#0', stretch = True, anchor='w') tv.column('size', width=100, anchor='center') tv.column('modified',anchor='center') tv.grid_rowconfigure(0, weight=1) tv.grid_columnconfigure(0, weight=1) tv.grid(row=0, column=0, sticky='nsew') #tv.pack(expand=True, fill='both') for path in paths: meta = path.stat() parent = str(path.parent) if parent == '.': parent = '' tv.insert(parent, 'end', iid=str(path), text=str(path.name), values=[meta.st_size, meta.st_mtime]) scrollbar = ttk.Scrollbar(root, orient=tk.VERTICAL, command=tv.yview) tv.configure(yscrollcommand=scrollbar.set) scrollbar.grid(row=0, column=1, sticky='nse') #scrollbar goes not to the left! root.mainloop()
解决方案
问题核心原因
Treeview的#0列是内置显示列,和自定义的size/modified列逻辑不同:
- 自定义列的内容存储在
values参数中,可通过tv.set(item, col)读取 #0列的内容是通过text参数设置的,tv.set()方法不支持访问该列,这就是报错的直接原因
基础修复代码
修改sort函数,针对#0列单独处理,用tv.item(item)['text']获取第一列的文本内容:
def sort(tv, col): itemlist = list(tv.get_children('')) # 针对#0列单独处理,用item方法获取text内容 if col == '#0': itemlist.sort(key=lambda x: tv.item(x)['text']) else: itemlist.sort(key=lambda x: tv.set(x, col)) for index, iid in enumerate(itemlist): tv.move(iid, tv.parent(iid), index)
可选优化:支持升降序切换+数字列正确排序
如果需要实现点击表头切换升降序,同时修复size列按字符串排序的问题(比如100排在20前面),可以修改代码如下:
# 新增全局变量记录各列的排序方向,默认升序 sort_directions = {'#0': 'asc', 'size': 'asc', 'modified': 'asc'} def sort(tv, col): itemlist = list(tv.get_children('')) # 获取当前排序方向并切换 direction = sort_directions[col] reverse = (direction == 'desc') if col == '#0': itemlist.sort(key=lambda x: tv.item(x)['text'], reverse=reverse) else: # size列转成整数排序,避免字符串排序错误 if col == 'size': itemlist.sort(key=lambda x: int(tv.set(x, col)), reverse=reverse) else: itemlist.sort(key=lambda x: tv.set(x, col), reverse=reverse) # 更新排序方向 sort_directions[col] = 'desc' if direction == 'asc' else 'asc' # 移动节点到排序后的位置 for index, iid in enumerate(itemlist): tv.move(iid, tv.parent(iid), index)
内容的提问来源于stack exchange,提问作者Paul-ET
相关产品推荐
相关产品推荐

