Changing text color when hovering over text with Tkinter?

python, tkinter

Solution

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)

Problem

So I have a bunch of text on a canvas in Tkinter and I want to make it so the text color changes when the mouse is hovering over the text. For the life of me I can't figure out how to do it, and there doesn't seem to be a lot of information about Tkinter anywhere. ``` for city in Cities: CityText = Cities[i] board.create_text(CityLocs[CityText][0], CityLocs[CityText][1], text=CityText, fill="white") CityText = Cities[i] i = i + 1 ``` That's just my code to place the text on the canvas, although I'm not sure what else to post to get my point across. Is there no 'hover' function or something like that built into Tkinter?

Original source