Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing text color when hovering over text with Tkinter?

Tags:

python

tkinter

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?

like image 992
Stephen Roda Avatar asked Apr 20 '12 02:04

Stephen Roda


People also ask

Can you change the text of a label in tkinter?

A label can include any text, and a window can contain many labels (just like any widget can be displayed multiple times in a window). You can easily change/update the Python Tkinter label text with the label text property. Changing the label's text property is another way to change the Tkinter label text.

How do I change the color of my cursor in Python?

To configure the mouse pointer color, we can specify the cursor value with (cursor type and its color). For example, to change the cursor color in a label widget, we can specify the value as, cursor="plus #aab1212" where "plus" defines the cursor type and #aab1212 is the Hex value of the color.

What is foreground in tkinter?

foreground − Foreground color for the widget. This can also be represented as fg. highlightbackground − Background color of the highlight region when the widget has focus. highlightcolor − Foreground color of the highlight region when the widget has focus.


2 Answers

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)

like image 92
jsbueno Avatar answered Sep 21 '22 13:09

jsbueno


Here's a (admittedly) pretty lame example that works on OS-X...

from Tkinter import *

master=Tk()
canvas=Canvas(master)
canvas.pack()
canvas.create_text((20,20),activefill="red",text="Hello World!",fill="black")
master.mainloop()

reference: http://effbot.org/tkinterbook/canvas.htm

like image 35
mgilson Avatar answered Sep 22 '22 13:09

mgilson