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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 15:13:15