Python Treeview排序后如何保持交替行颜色?
Hey there! The issue you're seeing happens because you're assigning fixed tags (tgOddRow/tgEvenRow) to each row when inserting them. When you sort the Treeview, rows reorder but their tags stay tied to the original data—so the colors don't follow the new row positions.
Luckily, there's a much cleaner solution that doesn't require re-tagging all rows after every sort: use ttk's built-in style support for alternating row colors. Here's how to implement it:
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) return super().heading(column, **kwargs) 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) self.heading(column, command=partial(callback, column, not reverse)) def _sort_by_name(self, column, reverse): self._sort(column, reverse, str, self._sort_by_name) objWindow = objTK.Tk() # Create and configure a style for alternating rows style = objTTK.Style(objWindow) style.configure("Treeview", rowheight=20) # Use ttk's native odd/even row states to auto-manage colors style.map("Treeview", background=[('odd', 'white'), ('even', 'blue')], foreground=[('odd', 'black'), ('even', 'black')]) arrlbHeader = ["Type" , "Description"] treeview = MyTreeview(columns=arrlbHeader, show="headings", style="Treeview") 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]) treeview.pack() # No manual tag setup needed anymore—style handles coloring automatically for row in arrRows: treeview.insert("", "end", values=row) objWindow.bind("<Escape>", lambda funcWinSer: objWindow.destroy()) objWindow.mainloop()
Why this works:
- ttk Treeview has native
oddandevenrow states that update automatically whenever row positions change (like after sorting). The style uses these states to apply colors dynamically, so you never have to manually update tags. - You can scrap all the old tag configuration and row-tagging code—this approach is far cleaner and more efficient, especially for 2000+ rows.
- The style-based coloring is handled by the ttk engine under the hood, so it’s optimized and won’t cause performance hits after sorts.
If you absolutely need to stick with custom tags (for example, if you have additional row-specific styling logic), you can optimize the re-tagging process by integrating it directly into your sort method:
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) # Update tag based on the new row position self.item(k, tags="tgEvenRow" if index % 2 == 0 else "tgOddRow") self.heading(column, command=partial(callback, column, not reverse))
But for your specific use case of maintaining alternating row colors after sorting, the style-based method is the best, most low-maintenance solution.
内容的提问来源于stack exchange,提问作者Sandeep S D




