2012-04-20 27 views
5

Tengo un montón de texto en un lienzo en Tkinter y quiero hacerlo para que el color del texto cambie cuando el mouse está sobre el texto. Por mi vida no puedo encontrar la manera de hacerlo, y no parece haber mucha información sobre Tkinter en ninguna parte.¿Cambiar el color del texto cuando se pasa el mouse sobre el texto con Tkinter?

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 

Ese es solo mi código para colocar el texto en el lienzo, aunque no estoy seguro de qué más publicar para expresar mi opinión. ¿No hay función 'hover' o algo así como integrado en Tkinter?

+1

Es posible que desee añadir etiquetas y/o almacenar los identificadores de los objetos de texto que está creando para que pueda acceder a ellos más tarde –

Respuesta

3

Aquí hay una (la verdad) ejemplo bastante cojo que funciona en 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() 

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

+0

No está mal, pero sólo funcionará para los elementos de texto dentro de un objeto canvas - Los widgets arbitrarios fuera un lienzo no tiene un atributo 'relleno' o 'relleno activo'. – jsbueno

+0

@jsbueno: Por supuesto, bind es más aplicable en general como lo ha señalado. (Ese fue mi primer pensamiento también ...), pero preguntó sobre los elementos de texto en un lienzo y esto es mucho más simple que enlazar eventos arbitrarios. Además, ¿puede vincular eventos a item_handles generados por el método create_text? De lo contrario, la tarea de rastrear qué elemento de texto se encuentra debajo del cursor se vuelve aún más difícil. – mgilson

+2

sí, puedes, 'item = canvas.create_text (...); canvas.tag_bind (artículo, "", devolución de llamada) '. Además, como sugiere el comentario de Joel, puede agregar una etiqueta a todos los elementos correspondientes 'create_text (..., tag =" city_name ")' y realizar un enlace en esta etiqueta. – FabienAndre

2

Puede enlazar eventos arbitrarios (ratón, teclado, gestor de ventanas y posiblemente otros) a cualquier widget en Tkinter.

Una documentación agradable para que sea al http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm -

Por ejemplo, para enlazar los cambios de color a los widgets cuando Pase el ratón sobre ellos:

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() 

El uso de functools.partial aquí le permite volver a utilizar una variable para su widget de texto (Etiqueta), ya que los agrega a una lista. Si uno se conforma con simplemente usar lambda, tendría una sorpresa desagradable, ya que la variable que hace referencia al widget en el cuerpo de la función lambda siempre apuntaría al último valor que tenía dentro del bucle for. functools.partial "congelar" el contenido variable en el momento en que se lo llama y produce una nueva función.

Sin embargo, como está colocando los elementos en un Canas, puede establecer los atributos "fill" y "fillactive" para cada elemento, como en la respuesta de @ mgilson, o puede crear una clase más genérica para manejar solo flotando, pero otros eventos eliges implementar más tarde.

Si su clase tiene un método __call__, puede pasar una instancia de la misma al método bind del lienzo, de modo que se llame al objeto resultante para cada evento en el lienzo. En este caso, evento de ratón de movimiento suficiente: (. Ps ejemplo, la colocación de la lona y el texto tomado de la respuesta de @ mgilson)

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() 

+0

Esta es una gran respuesta si los gerentes de geometría 'pack' o' grid' son suficientes para su colocación de texto ... Supongo que el gestor de geometría 'place' podría ser usado también ... pero eso se pone feo bastante rápido, creo ... – mgilson

+0

@mgilson: de hecho, al parecer, el OP realmente necesita Canvas, este nuevo ejemplo debería cubrirlo de una manera más genérica. (Pensé que uno de los eventos enlazaba los eventos con un elemento de lienzo, cuando escribí la respuesta por primera vez, necesitará algún administrador de eventos para volver a distribuir los eventos a elementos como la clase en el segundo ejemplo aquí) – jsbueno

+0

No lo probé, pero se ve bastante sólido. Mi única reserva es que parece que tu clase * siempre * elegirá un elemento para que tenga color con on_color (siempre y cuando el cursor esté en el lienzo de todos modos). Es posible si las etiquetas son lo suficientemente escasas como para que haya momentos en los que sería deseable no tener ninguno activo (si el cursor no está lo suficientemente cerca, por ejemplo) o si el cursor se va (aunque probablemente sea una solución más fácil) , establezca el color de previous_item en off_color y establézcalo en None en un método que esté vinculado a ""). – mgilson

Cuestiones relacionadas