17

How can I set a style for treeview widgets so that alternate rows have different background colors, for example, rows 1,3,5 have white backgrounds and rows 2,4,6 have light blue-grey backgrounds?

I'd also like to set gridlines.

stovfl
  • 14,998
  • 7
  • 24
  • 51
foosion
  • 7,619
  • 25
  • 65
  • 102

6 Answers6

50

I had this same issue a few months ago.

From the tk docs:

You can assign a list of tags to each item using the "tags" 
item configuration option (again, when creating the item or later on).

Tag configuration options can then be specified, which will then 
apply to all items having that tag.

Basically, you apply one tag to all of the odd-numbered rows, a different tag to each of the even-numbered rows, and then configure the tags.


When you create the items inside the treeview, add tags to them:

tree.insert('', 'end', text = 'your text', tags = ('oddrow',))

This code creates an element in tree, and the tags argument assigns the tag 'oddrow' to the element.

Once you've created all your elements with 'oddrow' and 'evenrow' tags, you can color the tags:

tree.tag_configure('oddrow', background='orange')
tree.tag_configure('evenrow', background='purple')
nbro
  • 15,395
  • 32
  • 113
  • 196
Matt Fenwick
  • 48,199
  • 22
  • 128
  • 192
  • 2
    Do you have any sample code or any more info? I can't figure out how to implement from the description in the docs. – foosion Oct 24 '11 at 21:04
  • Thank you. Now if we can just figure out how to add grid lines ... :) – foosion Oct 25 '11 at 16:15
  • I'll likely have related questions. If so, I'll start a new topic. – foosion Oct 25 '11 at 17:09
  • How to change color of a specific row without using tags? Is it possible with iid? I have a treeview with directory tree, I need to change color of a specific row, when it is selected and click a button. – TiYan Nov 29 '21 at 15:17
3

I realise this is an old question but just for the record configuring the tags just after creating the tree (i.e. when no items have yet been added to it) also works. As items get inserted later on they will be given the background colour appropriate to their 'oddrow' or 'evenrow' tag.

  • I think Colin meant that you can first configure tags, then add rows, and rows will be colored. No need to configure tags after adding all the rows as Matt's answer implies. – akarilimano Dec 28 '16 at 05:00
1

this is runnable without any extra modules... could mess with the code to make it work with your own.

from Tkinter import *
import ttk

class Test(Frame):

    def __init__(self):
        Frame.__init__(self)
        self.pack()
        self.listbox()
        self.buttons()

    def listbox(self):
        global new_customer_lb

        scrollbar = Scrollbar(self, orient="vertical")
        new_customer_lb = ttk.Treeview(self, columns=('ID','First Name','Last Name'))
        new_customer_lb['show']='headings'
        new_customer_lb.heading('#1', text= 'ID')
        new_customer_lb.column('#1', width=50, stretch=NO)
        new_customer_lb.heading('#2', text= 'First Name')
        new_customer_lb.column('#2', width=100, stretch=NO)
        new_customer_lb.heading('#3', text= 'Last Name')
        new_customer_lb.column('#3', width=100, stretch=NO)
        new_customer_lb.configure(yscroll = scrollbar.set, selectmode="browse")
        scrollbar.config(command=new_customer_lb.yview)
        new_customer_lb.pack()


    def buttons(self):
        load = Button(self, text='show customers', command=lambda:self.load_working_customers())
        test = Button(self, text='test new colors', command=lambda:self.test_colors())
        load.pack()
        test.pack()

    def load_working_customers(self):
        new_customer_lb.delete(*new_customer_lb.get_children())
        for a in range(0,10):            
            new_customer_lb.insert('','end', values=(a,'first','last'))

    def test_colors(self):
        new_customer_lb.delete(*new_customer_lb.get_children())                 

        new_customer_lb.tag_configure("evenrow",background='white',foreground='black')
        new_customer_lb.tag_configure("oddrow",background='black',foreground='white')
        for a in range(0,10):            
            if a % 2 == 0:
                new_customer_lb.insert('','end', values=(a,'first','last'), tags=('evenrow',))
            if a % 2 != 0:
                new_customer_lb.insert('','end', values=(a,'first','last'), tags=('oddrow',))

root = Tk()
app = Test()
app.mainloop()
ricky6991
  • 53
  • 9
  • with 'a' already a number its easier to use the %. in the event that you dont have a column with numbers, you could make a column populate with numbers an make it hidden then use the hidden column numbers to attach tags. also there is the iid that is auto placed with each row but i personally havent figured out getting the iid into int() form to use the % with. – ricky6991 Mar 23 '18 at 06:04
  • Doesn't run: ./demo3.py: line 1: from: command not found ./demo3.py: line 2: import: command not found ./demo3.py: line 4: syntax error near unexpected token `(' ./demo3.py: line 4: `class Test(Frame):' – user216652 Nov 16 '19 at 09:45
0

This is to create a SQL db. then loads the few customers from db into listbox. then you can click test new colors button to show it changing colors for odd rows. this is runnable as long as you have sqlalchemy installed as module.

from Tkinter import *
import ttk
from sqlalchemy import Column, ForeignKey, Integer, String, Text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

base = declarative_base()


class Customer(base):
    __tablename__='Customer_Details'
    Id = Column(Integer, primary_key=True)
    first_name = Column(String(64))
    last_name = Column(String(64))


class DB_connection(object):
    def __enter__(variable):
        variable.engine = create_engine("sqlite:///example.db")
        base.metadata.bind = variable.engine
        variable.DBSession = sessionmaker(bind=variable.engine)
        variable.Session = variable.DBSession
        variable.session = variable.Session()
        return variable
    def __exit__(variable, exc_type, exc_val, exc_tb):
        variable.session.commit()
        variable.session.close()

class Test(Frame):

    def __init__(self):
        Frame.__init__(self)
        self.pack()
        self.listbox()
        self.buttons()

    def listbox(self):
        global new_customer_lb

        scrollbar = Scrollbar(self, orient="vertical")
        new_customer_lb = ttk.Treeview(self, columns=('ID','First Name','Last Name'))
        new_customer_lb['show']='headings'
        new_customer_lb.heading('#1', text= 'ID')
        new_customer_lb.column('#1', width=50, stretch=NO)
        new_customer_lb.heading('#2', text= 'First Name')
        new_customer_lb.column('#2', width=100, stretch=NO)
        new_customer_lb.heading('#3', text= 'Last Name')
        new_customer_lb.column('#3', width=100, stretch=NO)
        new_customer_lb.configure(yscroll = scrollbar.set, selectmode="browse")
        scrollbar.config(command=new_customer_lb.yview)
        new_customer_lb.pack()


    def buttons(self):
        db = Button(self, text='make DB', command=lambda:self.create_db())
        customer = Button(self, text='create customers', command=lambda:self.create_customers())
        load = Button(self, text='show customers', command=lambda:self.load_working_customers())
        test = Button(self, text='test new colors', command=lambda:self.test_colors())
        db.pack()
        customer.pack()
        load.pack()
        test.pack()

    def create_db(self):
        print("start create db function")
        engine = create_engine('sqlite:///example.db')
        base.metadata.create_all(engine)
        print("Success create db function")

    def create_customers(self):
        print ('Start add customer sql')
        customer1 = Customer(first_name='first1',last_name='last1')
        customer2 = Customer(first_name='first2',last_name='last2')
        customer3 = Customer(first_name='first3',last_name='last3')
        customer4 = Customer(first_name='first4',last_name='last4')
        with DB_connection() as DB:
            DB.session.add_all([customer1,customer2,customer3,customer4])
        print ('sucess add customer sql')

    def load_working_customers(self):
        new_customer_lb.delete(*new_customer_lb.get_children())    
        with DB_connection() as DB:
            for a,b,c in DB.session.query(Customer.Id,Customer.first_name,Customer.last_name).order_by(Customer.Id):
                new_customer_lb.insert('','end', values=(a,b,c))

    def test_colors(self):
        new_customer_lb.delete(*new_customer_lb.get_children())                 

### configure even and odd here
        new_customer_lb.tag_configure("evenrow",background='white',foreground='black')
        new_customer_lb.tag_configure("oddrow",background='black',foreground='white')

        with DB_connection() as DB:
## this loop will take 'a' (Customer.Id) and test if even or odd
            for a,b,c in DB.session.query(Customer.Id,Customer.first_name,Customer.last_name).order_by(Customer.Id):                
                if a % 2 == 0:
                    new_customer_lb.insert('','end', values=(a,b,c), tags=('evenrow',))
                else:
                    new_customer_lb.insert('','end', values=(a,b,c), tags=('oddrow',))

root = Tk()
app = Test()
app.mainloop()
ricky6991
  • 53
  • 9
0

working code: python3.6

try:
    from Tkinter import *
    from ttk import *
except ImportError:  # Python 3
    from tkinter import *
    from tkinter.ttk import *

class App(Frame):

    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.CreateUI()
        self.LoadTable()
        self.grid(sticky = (N,S,W,E))
        parent.grid_rowconfigure(0, weight = 1)
        parent.grid_columnconfigure(0, weight = 1)

    def CreateUI(self):
        style = Style(self)
        
        style.theme_use("clam")
        style.configure("Treeview.Heading", background="black", foreground="white")        
        
        style.configure("Treeview",
                        background = "silver",
                        foreground = "black",
                        rowheight = 25,
                        fieldbackground = "silver",                
                        )
        style.map('Treeview', background=[('selected', 'green')])

        
        tv = Treeview(self)
        tv['columns'] = ('filename', 'environment', 'status')
        tv.heading("#0", text='Job Id')
        tv.column("#0", anchor="w", width=100)
        tv.heading('filename', text='File Name')
        tv.column('filename', anchor='w')
        tv.heading('environment', text='Environment')
        tv.column('environment', anchor='w', width=100)
        tv.heading('status', text='Status')
        tv.column('status', anchor='w', width=100)        
        tv.grid(sticky = (N,S,W,E))
        self.treeview = tv
        self.grid_rowconfigure(0, weight = 1)
        self.grid_columnconfigure(0, weight = 1)
        
        

    def LoadTable(self):
        self.treeview.tag_configure('oddrow', background = "#D3D3D3")
        self.treeview.tag_configure('evenrow', background = "#000000")
        self.treeview.insert('', 'end', text="First", iid=0,values=('10:00',
                             '10:10', 'Ok'), tags=('oddrow'))
        
        self.treeview.insert('', 'end', text="First", iid=1,values=('10:00',
                             '10:10', 'Ok'), tags=('evenrow'))

def main():
    root = Tk()
    App(root)
    root.mainloop()

if __name__ == '__main__':
    main()
Abhijith M
  • 743
  • 5
  • 5
0

I made a function that applies alternating row color. This is a better way for those who are resorting the rows and need to recolor correctly again.

def apply_striped_row_color(tv, oddcolor='lightgray', evencolor='white'):
    for index, iid in enumerate(tv.get_children()):
        tags = tv.item(iid,'tags')  # get current tags
        tags.remove('evenrow') if 'evenrow' in tags else None  # remove if exist
        tags.remove('oddrow') if 'oddrow' in tags else None  # remove if exist
        tags.append('evenrow' if index%2 else 'oddrow')
        self.item(iid, tags=tags)
    tv.tag_configure('oddrow', background=oddcolor)
    tv.tag_configure('evenrow', background= evencolor)
Youstanzr
  • 605
  • 1
  • 8
  • 16