python ttk treeview sort numbers
Question
I'm trying to use the ttk.Treeview sort function illustrated in the answer to this question (Tk treeview column sort) and it works just fine for strings like 'abc', 'bcd', 'cde', etc., but when I try to sort numbers it ends up showing up like this:
1
10
11
2
3
...
I'd like for the data to be sorted such that the output is:
1
2
3
...
10
11
I know that the values in the treeview columns are strings and that I'm most likely going to need to convert them to integers before sorting, but I can't figure out how to do that.
Solution
list.sort
method, sorted
function accept optional key
parameter. The return value of the function is used as comparison key.
Specifying key
function that convert the treeview item into number will solve your problem.
Example:
try:
from tkinter import *
from tkinter import ttk
except ImportError:
from Tkinter import *
import ttk
def treeview_sort_column(tv, col, reverse):
l = [(tv.set(k, col), k) for k in tv.get_children('')]
l.sort(key=lambda t: int(t[0]), reverse=reverse)
# ^^^^^^^^^^^^^^^^^^^^^^^
for index, (val, k) in enumerate(l):
tv.move(k, '', index)
tv.heading(col,
command=lambda: treeview_sort_column(tv, col, not reverse))
root = Tk()
columns = ('number',)
treeview = ttk.Treeview(root, columns=columns, show='headings')
for t in ('1', '10', '11', '2', '3'):
treeview.insert('', END, values=(t,))
treeview.pack()
for col in columns:
treeview.heading(col, text=col,
command=lambda c=col: treeview_sort_column(treeview, c, False))
mainloop()
OTHER TIPS
I figure I'd add this bit of code for anyone wanting to use the above solution for both regular string sorts and numeric sorts.
def treeview_sort_column(tv, col, reverse):
l = [(tv.set(k, col), k) for k in tv.get_children('')]
try:
l.sort(key=lambda t: int(t[0]), reverse=reverse)
# ^^^^^^^^^^^^^^^^^^^^^^^
except ValueError:
l.sort(reverse=reverse)
for index, (val, k) in enumerate(l):
tv.move(k, '', index)
tv.heading(col, command=lambda: treeview_sort_column(tv, col, not reverse))
It took me a while to find a variant of this answer, but I thought I would post an answer for those looking to sort dates as a string (i.e. 'DD/MM/YYYY')
import datetime
def treeview_sort_column(tv, col, reverse):
l = [(tv.set(k, col), k) for k in tv.get_children('')]
l.sort(key=lambda: x, datetime.datetime.strptime(x[0], '%d/%m/%y'), reverse=reverse)
for index, (val, k) in enumerate(l):
tv.move(k, '', index)
tv.heading(col, command=lambda: treeview_sort_column(tv, col, not reverse))