2

I have been working with the Tkinter ttk.Treeview widget lately and I have been able to change a lot the widget's style using a ttk.Style, but sadly I am unable to find a solution to this problem:

How can I change the item's colour when the cursor/mouse is over?

Like the activebackground option of Tkinter.Button. Like the VS CODE treeview: When you are navigating the explorer, the file/ folder under the cursor changes the background colour.

ChristianYami
  • 586
  • 1
  • 9
  • 17
  • `Events` may help – SNR Jan 07 '21 at 13:44
  • This is the virtual events available for the `ttk.Treeview` structure: https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/ttk-Treeview-events.html - Furthermore, you can use the `` and `` event for making effects when you mouseover something – oskros Jan 07 '21 at 14:02
  • There is also an event called `` which is activated whenever you move your mouse. – oskros Jan 07 '21 at 14:03
  • Found a solution for you: https://python-forum.io/Thread-bind-hover-on-tkinter-ttk-Treeview – oskros Jan 07 '21 at 14:06

2 Answers2

4

You can control the color of a row with a tag, so the first part of the solution is to define a tag to highlight a row:

tree.tag_configure('highlight', background='lightblue')

Next, write a method that will remove that tag from all items in the tree and then add it for the item under the cursor. The underlying tk widget has methods for adding and removing tags but those methods aren't exposed, so we'll need to directly call the underlying tk code.

def highlight_row(event):
    tree = event.widget
    item = tree.identify_row(event.y)
    tree.tk.call(tree, "tag", "remove", "highlight")
    tree.tk.call(tree, "tag", "add", "highlight", item)

Finally, bind the function to the <Motion> event:

tree.bind("<Motion>", highlight_row)

Here is a complete working example:

import tkinter as tk
from tkinter import ttk


def highlight_row(event):
    tree = event.widget
    item = tree.identify_row(event.y)
    tree.tk.call(tree, "tag", "remove", "highlight")
    tree.tk.call(tree, "tag", "add", "highlight", item)

root = tk.Tk()

tree = ttk.Treeview(root, style = 'W.TButton')
vsb = ttk.Scrollbar(root, command=tree.yview)
tree.configure(yscrollcommand=vsb.set)

vsb.pack(side="right", fill="y")
tree.pack(side="left", fill="both", expand=True)

tree.tag_configure('highlight', background='lightblue')
tree.bind("<Motion>", highlight_row)


for i in range(100):
    tree.insert("", "end", text=f"Item #{i+1}")
    tree.tag_bind(i, '<Motion>', highlight_row)

root.mainloop()

screenshot

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
0

Here is an example to do it. You may further improve this code.

import tkinter as tk
from tkinter import ttk


def Enter_event(event):

    for x in tree.get_children():
        tree.tag_configure(tree.item(x)['tags'], background='')

    tree.tag_configure(tree.item(tree.identify_row(event.y))['tags'], background='yellow')

root = tk.Tk()
style = ttk.Style() 
  
  
style.configure('W.TButton') 

tree = ttk.Treeview(root, style = 'W.TButton')

tree.pack()
for i in range(10):
    tree.insert("", "end", text="Item %s" % i, tags=i)
    tree.tag_bind(i, '<Motion>', Enter_event)
        
root.mainloop()

Explanation:

use set each cell a tag then bind each tag to motion event and call event handler.

  • tree.item(x)['tags'] returns the tag of specified iid.

  • tree.get_children() returns all the children iid

  • tree.identify_row(event.y) returns the row at y position.

  • tree.tag_configure(tree.item(tree.identify_row(event.y))['tags'], background='yellow') will change the background of the specified tag.

I tried Enter and leave event but it's not being recognized. (Also, note setting style configure to 'Treeview' doesn't work for me. If it does for any of the readers pls inform me)

JacksonPro
  • 3,135
  • 2
  • 6
  • 29