Is there a way that the alternative row colouring can be maintained after sorting? My treeview has 2,000 rows and would like to know if there is any solution other than retagging all the rows each time a column is sorted. When you click on any column, the row colouring gets mixed up.
Environment: Python 3.10.0 Windows 21H1
import tkinter as objTK
from tkinter import ttk as objTTK
from functools import partial
# Custom column sort for treeview
class MyTreeview(objTTK.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)
# End of if
# End of if
return super().heading(column, **kwargs)
# End of heading()
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)
# End of for loop
self.heading(column, command=partial(callback, column, not reverse))
# End of _sort()
def _sort_by_name(self, column, reverse):
self._sort(column, reverse, str, self._sort_by_name)
# End of _sort_by_num()
# End of class MyTreeview
objWindow = objTK.Tk()
arrlbHeader = ["Type" , "Description"]
treeview = MyTreeview(columns=arrlbHeader, show="headings")
arrRows = [
["Expenses", "Gen"],
["Expenses", "Aug"],
["Expenses", "Aug"],
["Income", "Aug"],
["Expenses", "Aug"]
]
arrColWidth = [70, 80]
arrColAlignment = ["center", "e"]
# Column header and attributes
arrSortType = ["name", "name"]
for iCount in range(len(arrlbHeader)):
strHdr = arrlbHeader[iCount]
treeview.heading(strHdr, text=strHdr.title(), sort_by=arrSortType[iCount])
treeview.column(arrlbHeader[iCount], width=arrColWidth[iCount], stretch=True, anchor=arrColAlignment[iCount])
# End of for loop
treeview.pack()
# Row colouring tags
treeview.tag_configure("tgOddRow", background="white")
treeview.tag_configure("tgEvenRow", background="blue")
# Insert rows
for iCount in range(len(arrRows)):
if iCount % 2 == 0:
treeview.insert("", "end", values=arrRows[iCount], tags="tgEvenRow")
else:
treeview.insert("", "end", values=arrRows[iCount], tags="tgOddRow")
# End of for loop
objWindow.bind("<Escape>", lambda funcWinSer: objWindow.destroy())
objWindow.mainloop()
CodePudding user response:
The solution is to retag all of the items. The treeview widget can retag a couple thousand rows in a tiny fraction of a second.
Here's a simple example. It assumes you don't have items nested under other items. If you do, it's fairly straightforward to account for that.
def retag():
tag = "tgOddRow"
for iid in treeview.get_children(""):
tag = "tgOddRow" if tag == "tgEvenRow" else "tgEvenRow"
treeview.item(iid, tags=(tag,))
When I run that function on a treeview with 10,000 rows, it takes well under 100ms.