Нажатие на заголовок столбца и сортировка

Последнее обновление: 24.09.2022

С помощью параметра 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):

Рассмотрим действие функции по этапно:

  1. При добавлениии элементов в Treeview каждому из них присваивается идентификатор. Используя идентификатор, можно получить все значения элемента в Treeview. Это необходимо, чтобы отсортировать элементы:

    l = [(tree.set(k, col), k) for k in tree.get_children("")]

    Здесь вначале пробегаемся по всем элементам в Treeview с помощью метода tree.get_children(""). В метод передается пустая строка "", поскольку мы хотим получить элементы верхнего уровня (по сути строки таблицы). Соответственно переменная k здесь будет представлять идентификатор элемента

  2. Для каждого элемента с помощью метода set получаем с помощью идентификатора значение столбца строки:

    tree.set(k, col)

    Например, если col=0 (то есть сортировка идет по имени, то вызов tree.set(k, col) возвращает имя ("Tom", "Bob", "Sam").

  3. Полученное значение помещаем в кортеж:

    (tree.set(k, col), k)
  4. Из кортежей формируется список:

    l = [(tree.set(k, col), k) for k in tree.get_children("")]

    То есть если, к примеру, сортировка идет по имени, то на выходе переменная l будет представлять список кортежей типа [("Tom", "I001"), ("Bob", "I002"), ("Sam", "I003")]

  5. Затем сортируем список с помощью встроенной метода sort():

    l.sort(reverse=reverse)

    В методе указываем направление сортировки с помощью параметра reverse

  6. Список отсортирован, но на отображение данных в таблице это пока никак не повлияло. Нам надо переупорядочить строки, привести их в соответствие с отсортированным списком l. Для этого переставляем их с помощью метода move():

    for index,  (_, k) in enumerate(l):
            tree.move(k, "", index)
    

    Сначала с помощью функции enumerate() из списка l получаем набор объектов, который состоит из индекса и собственно данных. При переборе этого набора индекс получаем в переменную index, а набор данных в кортеж (_, k) - первый элемент кортежа представляет имя, но здесь оно нам уже не нужно, оно использовалось на предыдущем шаге для сортировки. А второй элемент кортежа - идентификатор строки.

    В цикле с помощью вызова tree.move(k, "", index) перемещаем элемент с идентификатором k, который является элементов верхнего уровня (второй аргумент - "") на позицию с индексом index.

  7. На финальной стадии переустанавливаем определение заголовка:

    tree.heading(col, command=lambda: sort(col, not reverse))

    Параметр command в качестве выполняемой функции получает лямбда-выражение, которое вызывает функцию sort. При этом функции передается противоположное направление сортировки. Благодаря этому при следующем нажатии на заголовок сортировка будет идти в противоположном направлении.

Результат работы программы:

Сортировка и обработка нажатия на заголовок в Treeview в tkinter и python
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850