С помощью параметра command метода heading() можно привязать к заголовку некоторую функцию, которая будет вызываться по нажатию на заголовок.
treeview.heading(имя_заголовка, command=функция)
Рассмотрим на примере сортировки:
from tkinter import *
from tkinter import ttk
root = Tk()
root.title("METANIT.COM")
root.geometry("250x200")
# определяем данные для отображения
people = [("Tom", 38, "tom@email.com"), ("Bob", 42, "bob@email.com"), ("Sam", 28, "sam@email.com")]
# определяем столбцы
columns = ("name", "age", "email")
tree = ttk.Treeview(columns=columns, show="headings")
tree.pack(expand=1, fill=BOTH)
def sort(col, reverse):
# получаем все значения столбцов в виде отдельного списка
l = [(tree.set(k, col), k) for k in tree.get_children("")]
# сортируем список
l.sort(reverse=reverse)
# переупорядочиваем значения в отсортированном порядке
for index, (_, k) in enumerate(l):
tree.move(k, "", index)
# в следующий раз выполняем сортировку в обратном порядке
tree.heading(col, command=lambda: sort(col, not reverse))
# определяем заголовки
tree.heading("name", text="Имя", anchor=W, command=lambda: sort(0, False))
tree.heading("age", text="Возраст", anchor=W, command=lambda: sort(1, False))
tree.heading("email", text="Email", anchor=W, command=lambda: sort(2, False))
tree.column("#1", stretch=NO, width=70)
tree.column("#2", stretch=NO, width=60)
tree.column("#3", stretch=NO, width=100)
# добавляем данные
for person in people:
tree.insert("", END, values=person)
root.mainloop()
Как и в предыдущих примерах, виджет Treeview использует список кортежей people и представляет таблицу с тремя столбцами.
Для сортировки определена функция sort(), которая принимает два параметра: col(номер столбца, по которому идет сортировка) и reverse (направление сортировки - по возрастанию или убыванию)
def sort(col, reverse):
Рассмотрим действие функции по этапно:
При добавлениии элементов в Treeview каждому из них присваивается идентификатор. Используя идентификатор, можно получить все значения элемента в Treeview. Это необходимо, чтобы отсортировать элементы:
l = [(tree.set(k, col), k) for k in tree.get_children("")]
Здесь вначале пробегаемся по всем элементам в Treeview с помощью метода tree.get_children(""). В метод передается пустая строка "", поскольку мы хотим получить
элементы верхнего уровня (по сути строки таблицы). Соответственно переменная k здесь будет представлять идентификатор элемента
Для каждого элемента с помощью метода set получаем с помощью идентификатора значение столбца строки:
tree.set(k, col)
Например, если col=0 (то есть сортировка идет по имени, то вызов tree.set(k, col) возвращает имя ("Tom", "Bob", "Sam").
Полученное значение помещаем в кортеж:
(tree.set(k, col), k)
Из кортежей формируется список:
l = [(tree.set(k, col), k) for k in tree.get_children("")]
То есть если, к примеру, сортировка идет по имени, то на выходе переменная l будет представлять список кортежей типа [("Tom", "I001"), ("Bob", "I002"), ("Sam", "I003")]
Затем сортируем список с помощью встроенной метода sort():
l.sort(reverse=reverse)
В методе указываем направление сортировки с помощью параметра reverse
Список отсортирован, но на отображение данных в таблице это пока никак не повлияло. Нам надо переупорядочить строки, привести их в соответствие с отсортированным списком l. Для этого переставляем их с помощью метода move():
for index, (_, k) in enumerate(l):
tree.move(k, "", index)
Сначала с помощью функции enumerate() из списка l получаем набор объектов, который состоит из индекса и собственно данных. При переборе этого набора индекс получаем в переменную index,
а набор данных в кортеж (_, k) - первый элемент кортежа представляет имя, но здесь оно нам уже не нужно, оно использовалось на предыдущем шаге для сортировки.
А второй элемент кортежа - идентификатор строки.
В цикле с помощью вызова tree.move(k, "", index) перемещаем элемент с идентификатором k, который является элементов верхнего уровня (второй аргумент - "") на позицию с индексом index.
На финальной стадии переустанавливаем определение заголовка:
tree.heading(col, command=lambda: sort(col, not reverse))
Параметр command в качестве выполняемой функции получает лямбда-выражение, которое вызывает функцию sort. При этом функции передается противоположное направление сортировки.
Благодаря этому при следующем нажатии на заголовок сортировка будет идти в противоположном направлении.
Результат работы программы: