Tk treeview列排序

时间:2009-12-27 20:18:33

标签: python sorting treeview tkinter

有没有办法通过点击列对Tk Treeview中的条目进行排序?令人惊讶的是,我找不到任何文档/教程。

5 个答案:

答案 0 :(得分:18)

来自#tcl

patthoyts指出TreeView Tk演示程序具有排序功能。这是Python的等价物:

def treeview_sort_column(tv, col, reverse):
    l = [(tv.set(k, col), k) for k in tv.get_children('')]
    l.sort(reverse=reverse)

    # rearrange items in sorted positions
    for index, (val, k) in enumerate(l):
        tv.move(k, '', index)

    # reverse sort next time
    tv.heading(col, command=lambda: \
               treeview_sort_column(tv, col, not reverse))

[...]
columns = ('name', 'age')
treeview = ttk.TreeView(root, columns=columns, show='headings')
for col in columns:
    treeview.heading(col, text=col, command=lambda: \
                     treeview_sort_column(treeview, col, False))
[...]

答案 1 :(得分:12)

这在python3中不起作用。由于变量是通过引用传递的,因此所有lambdas最终都引用了列中相同的最后一个元素。

这对我有用:

for col in columns:
    treeview.heading(col, text=col, command=lambda _col=col: \
                     treeview_sort_column(treeview, _col, False))

答案 2 :(得分:2)

madonius 是正确的,但是这里您有完整的示例以及正确且易懂的解释

Sridhar Ratnakumar 提供的答案在python3中(显然在python2.7中)不起作用:由于变量是通过引用传递的,因此所有lambda最终都引用相同的,最后一个元素在列中。

您只需要更改此for loop

for col in columns:
    treeview.heading(col, text=col, command=lambda _col=col: \
                     treeview_sort_column(treeview, _col, False))

并且必须对treeview_sort_column中的lambda函数应用相同的更改

因此完整的解决方案如下所示:

def treeview_sort_column(tv, col, reverse):
    l = [(tv.set(k, col), k) for k in tv.get_children('')]
    l.sort(reverse=reverse)

    # rearrange items in sorted positions
    for index, (val, k) in enumerate(l):
        tv.move(k, '', index)

    # reverse sort next time
    tv.heading(col, text=col, command=lambda _col=col: \
                 treeview_sort_column(tv, _col, not reverse))

[...]
columns = ('name', 'age')
treeview = ttk.TreeView(root, columns=columns, show='headings')
for col in columns:
    treeview.heading(col, text=col, command=lambda _col=col: \
                     treeview_sort_column(treeview, _col, False))
[...]

答案 3 :(得分:1)

在尝试为数据库创建视图时,我遇到了相同的问题,
Sridhar Ratnakumar答案的启发,
我宁愿采用与他相同的原则,并升级类Treeview。

class MyTreeview(ttk.Treeview):
    def heading(self, column, sort_by=None, **kwargs):
        if sort_by and not hasattr(kwargs, 'command'):
            func = getattr(self, f"_sort_by_{sort_by}", None)
            if func:
                kwargs['command'] = partial(func, column, False)
        return super().heading(column, **kwargs)

    def _sort(self, column, reverse, data_type, callback):
        l = [(self.set(k, column), k) for k in self.get_children('')]
        l.sort(key=lambda t: data_type(t[0]), reverse=reverse)
        for index, (_, k) in enumerate(l):
            self.move(k, '', index)
        self.heading(column, command=partial(callback, column, not reverse))

    def _sort_by_num(self, column, reverse):
        self._sort(column, reverse, int, self._sort_by_num)

    def _sort_by_name(self, column, reverse):
        self._sort(column, reverse, str, self._sort_by_name)

    def _sort_by_date(self, column, reverse):
        def _str_to_datetime(string):
            return datetime.strptime(string, "%Y-%m-%d %H:%M:%S")
        self._sort(column, reverse, _str_to_datetime, self._sort_by_date)

...
# Some code
...

treeview.heading('number', text='number', sort_by='num')
treeview.heading('name', text='name', sort_by='name')
treeview.heading('date', text='date', sort_by='date')

只需将其放在这里:)

答案 4 :(得分:0)

如果表中有整数,请对该函数进行小的更改 看起来像这样。

def treeview_sort_column(treeview: ttk.Treeview, col, reverse: bool):
    """
    to sort the table by column when clicking in column
    """
    try:
        data_list = [
            (int(treeview.set(k, col)), k) for k in treeview.get_children("")
        ]
    except Exception:
        data_list = [(treeview.set(k, col), k) for k in treeview.get_children("")]

    data_list.sort(reverse=reverse)

    # rearrange items in sorted positions
    for index, (val, k) in enumerate(data_list):
        treeview.move(k, "", index)

    # reverse sort next time
    treeview.heading(
        column=col,
        text=col,
        command=lambda _col=col: treeview_sort_column(
            treeview, _col, not reverse
        ),
    )