Tk treeview column sort

后端 未结 5 2072
旧巷少年郎
旧巷少年郎 2020-11-30 05:26

Is there a way to sort the entries in a Tk Treeview by clicking the column? Surprisingly, I could not find any documentation/tutorial for this.

相关标签:
5条回答
  • 2020-11-30 05:39

    make this small change to the function if you have integers in your table it will look like this.

    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
            ),
        )
    
    
    0 讨论(0)
  • 2020-11-30 05:49

    This did not work in python3. Since the Variable was passed by reference, all lambdas ended up refering to the same, last, element in columns.

    This did the trick for me:

    for col in columns:
        treeview.heading(col, text=col, command=lambda _col=col: \
                         treeview_sort_column(treeview, _col, False))
    
    0 讨论(0)
  • 2020-11-30 05:50

    madonius is right, but here you have the full example and a proper, understandable explanation

    The answer provided by Sridhar Ratnakumar does not work in python3 (and apparently in python2.7): since the variable is passed by reference, all lambdas end up referring to the same, last, element in columns.

    You just need to change this for loop:

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

    And the same change has to be applied to the lambda function inside treeview_sort_column

    So the complete solution would look like this:

    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))
    [...]
    
    0 讨论(0)
  • 2020-11-30 05:50

    I just encountered the same issue while trying to create a view for DB,
    Inspired by Sridhar Ratnakumar Answer,
    I rather take the same principles that he did and to upgrade the class 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')
    
    

    Just puting this here :)

    0 讨论(0)
  • 2020-11-30 05:55

    patthoyts from #tcl pointed out that the TreeView Tk demo program had the sort functionality. Here's the Python equivalent of it:

    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))
    [...]
    
    0 讨论(0)
提交回复
热议问题