Как реализовать сортировку БД таблицы tkinter по заголовку
Проблема - lambda не видит созданную функцию treeview_sort_column, пытался вынести функцию в класс main, но тогда появляется проблема с ключевыми командами в функции ('Treeview' object has no attribute 'item, move" и тд.) пример кода:
import sqlite3 # импорт модуля SQLite
import tkinter as tk # импорт библиотеки tkinter
from tkinter import ttk # импорт модуля TTk
class Main(tk.Frame):
def __init__(self, root):
super().__init__(root)
self.init_main()
self.db = db
self.view_records()
# noinspection PyTypeChecker
def init_main(self): # главное окно
toolbar = tk.Frame(bg='#d7d8e0', bd=2)
toolbar.pack(side=tk.TOP, fill=tk.X)
self.add_img = tk.PhotoImage('')
btn_open_dialog = tk.Button(toolbar, text='Добавить позицию', command=self.open_dialog, bg='#d7d8e0', bd=0,compound=tk.TOP, image=self.add_img)
btn_open_dialog.pack(side=tk.LEFT)
self.update_img = tk.PhotoImage('')
btn_edit_dialog = tk.Button(toolbar, text='Редактировать', bg='#d7d8e0', bd=0, image=self.update_img, compound=tk.TOP, command=self.open_update_dialog)
btn_edit_dialog.pack(side=tk.LEFT)
self.tree = ttk.Treeview(self, columns=('id', 'prefix', 'number', 'postfix', 'zavod', 'quantity', 'cons_date', 'ubd_date'), height=15, show='headings')
def treeview_sort_column(self, col, reverse):
l = [(self.item(k)["text"], k) for k in self.get_children()]
l.sort(key=lambda t: t[0], reverse=reverse)
for index, (val, k) in enumerate(l):
self.move(k, '', index)
self.heading(col, command=lambda: treeview_sort_column(self, col, not reverse))
self.tree.column('id', width=30, anchor=tk.CENTER)
self.tree.column('prefix', width=60, anchor=tk.CENTER)
self.tree.column('number', width=150, anchor=tk.CENTER)
self.tree.column('postfix', width=50, anchor=tk.CENTER)
self.tree.column('zavod', width=80, anchor=tk.CENTER)
self.tree.column('quantity', width=50, anchor=tk.CENTER)
self.tree.column('cons_date', width=100, anchor=tk.CENTER)
self.tree.column('ubd_date', width=100, anchor=tk.CENTER)
self.tree.heading('id', text='ID', command=lambda: self.treeview_sort_column(self.tree, 'id', False))
self.tree.heading('prefix', text='Префикс', command=lambda: self.treeview_sort_column(self.tree, "prefix", False))
self.tree.heading('number', text='Номенклатура', command=lambda: self.treeview_sort_column(self.tree, "number", False))
self.tree.heading('postfix', text='Суфикс', command=lambda: self.treeview_sort_column(self.tree, "postfix", False))
self.tree.heading('zavod', text='Завод', command=lambda: self.treeview_sort_column(self.tree, "zavod", False))
self.tree.heading('quantity', text='Ящ норма', command=lambda: self.treeview_sort_column(self.tree, "quantity", False))
self.tree.heading('cons_date', text='Дата консервации', command=lambda: self.treeview_sort_column(self.tree, "cons_date", False))
self.tree.heading('ubd_date', text='Дата введения', command=lambda: self.treeview_sort_column(self.tree, "ubd_date", False))
self.tree.pack()
Пробую реализовать вот эту сортировку Как реализовать сортировку в БД?, однако я, похоже, где-то ошибся и не вижу этого.
Ответы (1 шт):
У вас в коде вариант treeview_sort_column для сортировки по тексту из дерева (у вас дерево вообще отключено). Вам нужен вариант этой функции из этого вопроса. Также это отдельная функция, а не метод класса Main, поэтому не нужно пытаться вызывать ее как self.treeview_sort_column(...), иначе будет сыпать ошибками AttributeError: 'Main' object has no attribute 'treeview_sort_column'. Т.к. это не метод, то и не нужно переименовывать первый параметр в self, а оставить как есть.
Рабочий пример:
import tkinter as tk # импорт библиотеки tkinter
from tkinter import ttk # импорт модуля TTk
class Main(tk.Frame):
def __init__(self, root):
super().__init__(root)
self.init_main()
# self.db = db
self.view_records()
def view_records(self):
for i in range(10):
self.tree.insert("",0,values=(i,))
# noinspection PyTypeChecker
def init_main(self): # главное окно
toolbar = tk.Frame(bg='#d7d8e0', bd=2)
toolbar.pack(side=tk.TOP, fill=tk.X)
# self.add_img = tk.PhotoImage('')
# btn_open_dialog = tk.Button(toolbar, text='Добавить позицию', command=self.open_dialog, bg='#d7d8e0', bd=0,compound=tk.TOP, image=self.add_img)
# btn_open_dialog.pack(side=tk.LEFT)
# self.update_img = tk.PhotoImage('')
# btn_edit_dialog = tk.Button(toolbar, text='Редактировать', bg='#d7d8e0', bd=0, image=self.update_img, compound=tk.TOP, command=self.open_update_dialog)
# btn_edit_dialog.pack(side=tk.LEFT)
self.tree = ttk.Treeview(self, columns=('id', 'prefix', 'number', 'postfix', 'zavod', 'quantity', 'cons_date', 'ubd_date'), height=15, show='headings')
def treeview_sort_column(tv, col, reverse):
l = [(tv.set(k, col), k) for k in tv.get_children()]
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))
self.tree.column('id', width=30, anchor=tk.CENTER)
self.tree.column('prefix', width=60, anchor=tk.CENTER)
self.tree.column('number', width=150, anchor=tk.CENTER)
self.tree.column('postfix', width=50, anchor=tk.CENTER)
self.tree.column('zavod', width=80, anchor=tk.CENTER)
self.tree.column('quantity', width=50, anchor=tk.CENTER)
self.tree.column('cons_date', width=100, anchor=tk.CENTER)
self.tree.column('ubd_date', width=100, anchor=tk.CENTER)
self.tree.heading('id', text='ID', command=lambda: treeview_sort_column(self.tree, 'id', False))
self.tree.heading('prefix', text='Префикс', command=lambda: treeview_sort_column(self.tree, "prefix", False))
self.tree.heading('number', text='Номенклатура', command=lambda: treeview_sort_column(self.tree, "number", False))
self.tree.heading('postfix', text='Суфикс', command=lambda: treeview_sort_column(self.tree, "postfix", False))
self.tree.heading('zavod', text='Завод', command=lambda: treeview_sort_column(self.tree, "zavod", False))
self.tree.heading('quantity', text='Ящ норма', command=lambda: treeview_sort_column(self.tree, "quantity", False))
self.tree.heading('cons_date', text='Дата консервации', command=lambda: treeview_sort_column(self.tree, "cons_date", False))
self.tree.heading('ubd_date', text='Дата введения', command=lambda: treeview_sort_column(self.tree, "ubd_date", False))
self.tree.pack()
root = tk.Tk()
Main(root).pack()
root.mainloop()
По поводу более естественной сортировки, изменяем функцию таким образом:
def treeview_sort_column(tv, col, reverse, key=str):
l = [(tv.set(k, col), k) for k in tv.get_children()]
l.sort(reverse=reverse, key=lambda t: key(t[0]))
for index, (val, k) in enumerate(l):
tv.move(k, '', index)
tv.heading(col, command=lambda: treeview_sort_column(tv, col, not reverse, key=key))
Для числовых колонок в качестве параметра key передаем int (или float, если возможны дробные значения), для даты передаем функцию (в данном случае лябмда-функцию lambda s: datetime.strptime(s, "%d.%m.%Y") для даты формата DD.MM.YYYY, datetime импортируется как from datetime import datetime), конвертирующую дату в виде строки в объект даты, который потом нормально отсортируется при помощи sort. Для колонок со строковыми значениями можно ничего не передавать. Примеры:
self.tree.heading('id', text='ID', command=lambda: treeview_sort_column(self.tree, 'id', False, key=int))
self.tree.heading('prefix', text='Префикс', command=lambda: treeview_sort_column(self.tree, "prefix", False))
self.tree.heading('number', text='Номенклатура', command=lambda: treeview_sort_column(self.tree, "number", False))
self.tree.heading('postfix', text='Суфикс', command=lambda: treeview_sort_column(self.tree, "postfix", False))
self.tree.heading('zavod', text='Завод', command=lambda: treeview_sort_column(self.tree, "zavod", False))
self.tree.heading('quantity', text='Ящ норма', command=lambda: treeview_sort_column(self.tree, "quantity", False, key=int))
self.tree.heading('cons_date', text='Дата консервации', command=lambda: treeview_sort_column(self.tree, "cons_date", False, key=lambda s: datetime.strptime(s, "%d.%m.%Y")))
self.tree.heading('ubd_date', text='Дата введения', command=lambda: treeview_sort_column(self.tree, "ubd_date", False, key=lambda s: datetime.strptime(s, "%d.%m.%Y")))
Вообще, параметр key методов сортировки (list.sort или sorted) - это функция, которая применяется к каждому из сортируемых значений, по результатам выполнения этих функций в итоге выполняется сортировка. Документация.
Для сортировки смешанных данных (числа внутри строк, например что-то вроде "Изображение 10") можно использовать модуль natsort (установка через pip install natsort)