Почему не меняется цвет строки в Treeview?
Знаю что схожий вопрос задавал ранее (ссылка), но тут другая проблема. Мне дали ответ как можно изменять цвет строки в Treeview и он работает.
Вот сам пример:
import tkinter
from tkinter import ttk
root = tkinter.Tk ()
class MyTree(ttk.Treeview):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Элементам с тегом green назначить зеленый фон, элементам с тегом red назначить красный фон
self.tag_configure('A', background='green')
self.tag_configure('B', background='red')
self.tag_configure('C', background='yellow')
def insert(self, parent_node, index, **kwargs):
'''Назначение тега при добавлении элемента в дерево'''
item = super().insert(parent_node, index, **kwargs)
values = kwargs.get('values', None)
if values:
if values[0]=='BGH':
super().item(item, tag='A')
elif values[0]=='HBG':
super().item(item, tag='B')
elif values[0]=='GHB':
super().item(item, tag='C')
return item
def fixed_map(option):
return [elm for elm in style.map('Treeview', query_opt=option) if
elm[:2] != ('!disabled', '!selected')]
style = ttk.Style()
style.map('Treeview', foreground=fixed_map('foreground'),
background=fixed_map('background'))
style = ttk.Style (root)
style.configure ("Treeview", background="grey", fieldbackground="green")
tree = MyTree (root, columns=('Data','TRu'))
tree.heading ('#0', text='Item')
tree.heading ('#1', text='Data')
tree.heading ('#2', text='TRu')
tree.insert ("", "end", text="Item_0", values=('GHB','100'))
tree.insert ("", "end", text="Item_1", values=('BGH','200'))
lvl1 = tree.insert ("", "end", text="Item_2", values=('HBG','300'))
tree.insert (lvl1, "end", text="Item_0", values=('BGH','100'))
tree.pack ()
root.mainloop ()
В нем всё работает замечательно, но если я пробую использовать всё тоже самое, но только с БД sqlite3 и автоматическим выводом инфы из неё, то всё перестаёт работать.
Вот мой пример:
import tkinter as tk
from tkinter import ttk
import sys
import sqlite3
import os
class MyTree(ttk.Treeview):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Элементам с тегом green назначить зеленый фон, элементам с тегом red назначить красный фон
self.tag_configure('green', background='green')
self.tag_configure('red', background='red')
self.tag_configure('yellow', background='yellow')
def insert(self, parent_node, index, **kwargs):
'''Назначение тега при добавлении элемента в дерево'''
item = super().insert(parent_node, index, **kwargs)
values = kwargs.get('values', None)
if values:
if values[1]=="Сдана":
super().item(item, tag='green')
elif values[1]=="Просрочена":
super().item(item, tag='red')
elif values[1]=="На руках":
super().item(item, tag='yellow')
return item
class Main(tk.Tk):
def __init__(self,*args, **kwargs):
tk.Tk.__init__(self,*args, **kwargs)
self.title("Электронный читательский билет - Добавить книги в ЧБ")
#Заголовок
self.geometry("1000x450+300+200")#Размер
self.resizable(False, False)#Изменение размера окна
self.protocol("WM_DELETE_WINDOW", lambda: sys.exit())
self.s = ttk.Style(self)#Использование темы
self.s.theme_use('clam')
self.frame = tk.Frame(self)
self.frame.configure(background='gray60',width=1000,height=350)
self.frame.pack()
def fixed_map(option):
return [elm for elm in style.map('Treeview', query_opt=option) if elm[:2] != ('!disabled', '!selected')]
style = ttk.Style()
style.map('Treeview', foreground=fixed_map('foreground'), background=fixed_map('background'))
ttk.Style().configure("Treeview",fieldbackground="royalblue3")
#Таблица
self.table = MyTree(self.frame, columns=('DB','Class','litera','adr','phone'), height=16)
self.table.column('#0', width=210, anchor=tk.CENTER)
self.table.column('DB', width=210, anchor=tk.CENTER)
self.table.column('Class', width=150, anchor=tk.CENTER)
self.table.column('litera', width=30, anchor=tk.CENTER)
self.table.column('phone', width=150, anchor=tk.CENTER)
self.table.column('adr', width=230, anchor=tk.CENTER)
self.table.heading('#0', text='ФИО / Книга')
self.table.heading('DB', text='День рождения / Автор')
self.table.heading('Class', text='Класс / Статус')
self.table.heading('litera', text='Литера')
self.table.heading('phone', text='Телефон')
self.table.heading('adr', text='Адрес')
self.table.pack(side='left')
self.scroll = ttk.Scrollbar(self.frame, orient='vertical', command=self.table.yview)
self.scroll.pack(side='right',fill='y')
conn = sqlite3.connect(os.path.dirname(os.path.abspath(__file__))+"/LC.db")
cur = conn.cursor()
#Вывод всех учеников
cur.execute("SELECT * FROM STUD")
rows = cur.fetchall()
for row in rows:
lvl1 = self.table.insert("" , tk.END ,text=row[0], values=row[1:])
row1 = row[0],row[1],row[5]
cur.execute('SELECT BOOK, AUT, STAT FROM LC WHERE FIO=(?) and DB=(?) AND PHONE = (?)',row1)
books = cur.fetchall()
for book in books:
self.table.insert(lvl1, tk.END,text=book[0],values=book[1:])#По задумке тут должен меняться цвет(тут есть значения 'Сдана', 'На руках', 'Просрочена')
if __name__ == "__main__":
app = Main()
app.mainloop()
Подскажите, пожалуйста, что же не так в моём коде и почему не меняется цвет строки
PS Простите что нету самой БД, но там хранится личная информация.
Ответы (1 шт):
Подсветка работает с темой по-умолчанию, и не работает, если тему заменить на clam.
Чтобы понять в чем проблема, нужно подробнее разобраться с функцией fixed_map (функция изначально взята из сообщения в обсуждении на багтрекере python https://bugs.python.org/issue36468):
def fixed_map(option):
return [elm for elm in style.map('Treeview', query_opt=option) if elm[:2] != ('!disabled', '!selected')]
Здесь берется список параметров темы (в нашем случае - параметры цвета фона и шрифта элементов Treeview), и убираются те элементы списка, в которых первые два элемента равны '!disabled' и '!selected'.
Модифицируем функцию таким образом, чтобы видеть, что приходит на вход, и что получается на выходе:
def fixed_map(option):
print(option)
style_map = style.map('Treeview', query_opt=option)
print('До изменений:', style_map)
result = [elm for elm in style_map if elm[:2] != ('!disabled', '!selected')]
print('После изменений:', result)
return result
Закомментриуем изменение темы (self.s.theme_use('clam')), запускаем, получаем :
foreground
До изменений: [('disabled', 'SystemGrayText'), ('!disabled', '!selected', 'SystemWindowText'), ('selected', 'SystemHighlightText')]
После изменений: [('disabled', 'SystemGrayText'), ('selected', 'SystemHighlightText')]
background
До изменений: [('disabled', 'SystemButtonFace'), ('!disabled', '!selected', 'SystemWindow'), ('selected', 'SystemHighlight')]
После изменений: [('disabled', 'SystemButtonFace'), ('selected', 'SystemHighlight')]
Выводится то что и ожидалось, и строки в таблице подсвечиваются нормально. Раскомментируем изменение темы, запускаем еще раз, получаем такой вывод:
foreground
До изменений: [('disabled', '#999999'), ('!disabled', '!selected', 'black'), ('selected', '#ffffff')]
После изменений: [('disabled', '#999999'), ('selected', '#ffffff')]
background
До изменений: [('disabled', '#dcdad5'), ('!disabled !selected', '#ffffff'), ('selected', '#4a6984')]
После изменений: [('disabled', '#dcdad5'), ('!disabled !selected', '#ffffff'), ('selected', '#4a6984')]
Видим, что параметры фона заданы не так как мы ожидали: вместо двух отдельных элементов ('!disabled', '!selected') присутствует одна цельная строка '!disabled !selected', из-за этого параметр не удаляется.
Соответственно, чтобы с измененной темой подсветка работала, нужно модифицировать эту функцию таким образом:
def fixed_map(option):
return [elm for elm in style.map('Treeview', query_opt=option)
if elm[:2] != ('!disabled', '!selected') and elm[0] != '!disabled !selected']
Возможны какие-то еще сюрпризы, например параметры '!disabled' и '!selected' могут идти в другом порядке, при этом могут быть заданы одной строкой, или отдельно, тогда придется использовать более хитрое условие (элемент будет пропущен и если будет присутствовать только один из этих параметров):
def fixed_map(option):
return [elm for elm in style.map('Treeview', query_opt=option)
if not ({'!disabled', '!selected'} & set(' '.join(elm).split()))]