You can bind arbitrary events (mouse, keyboard, window manager and possibly others) to any widget in Tkinter.
A nice documentation for that is at http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm -
For example, to bind color changes to widgets when mouse hover over them:
import Tkinter
from functools import partial
def color_config(widget, color, event):
widget.configure(foreground=color)
parent = Tkinter.Tk()
text = Tkinter.Label(parent, text="Hello Text")
text.bind("<Enter>", partial(color_config, text, "red"))
text.bind("<Leave>", partial(color_config, text, "blue"))
text.pack()
Tkinter.mainloop()
The use of functools.partial
here allows you to re-use a variable for your text (Label) widget, since you are appending them to a list. If one would settle to simply using lambda you would have a disgusting surprise, as the variable referring to the widget in the body of the lambda function would always point to the last value it had inside the for
loop. functools.partial
"freeze" the variable content at the time it is called, and yields a new function.
However, since you are placing the items in a Canas, you can either set the "fill" and "fillactive" attributes for each item, as in @mgilson's answer, or you can create a more generic class to handle not only hovering, but other events you choose to implement later.
If your class has a __call__
method, you can pass an instance of it to the bind
method of the canvas, so that the resulting object is called for each event on the canvas. In this case, mouse-motion event suffices:
from Tkinter import *
class Follower(object):
def __init__(self,on_color="#fff", off_color="#000"):
self.on_color = on_color
self.off_color = off_color
self.previous_item = None
def hover(self, canvas, item, x, y):
x1, y1, x2, y2 = canvas.bbox(item)
if x1 <= x <= x2 and y1 <= y <= y2:
return True
return False
def __call__(self, event):
canvas = event.widget
item = canvas.find_closest(event.x, event.y)
hovering = self.hover(canvas, item, event.x, event.y)
if (not hovering or item != self.previous_item) and self.previous_item is not None:
canvas.itemconfig(self.previous_item, fill=self.off_color)
if hovering:
canvas.itemconfig(item, fill=self.on_color)
self.previous_item = item
master=Tk()
canvas=Canvas(master)
canvas.pack()
canvas.create_text((40,20),text="Hello World!",fill="black")
canvas.create_text((60,80),text="FooBar",fill="black")
canvas.bind("<Motion>", Follower())
master.mainloop()
(ps. canvas and text placement example borrowed from @mgilson's answer)