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.
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
),
)
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))
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))
[...]
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 :)
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))
[...]