ffrree
ffrree

Reputation: 93

tkinter widget to follow mouse movement

I tried to change the mouse tip with a Canvas created red cirlce OR a yellow Label with "X" on it.

I used a "where" fucntion, which traps the mouse movement, and provides me with the current position of the mouse tip, so place either one of the above tips, ie red circle or yellow label at the mounse tip position.

I realise that if they are placed right at the mouse tip, is not so desirable as it can mask the underlying widgets, but let's put that aside.

Using the following code, you'll realize that the selected tip is offset from the actual mouse tip, while I actually place then right at the tip. So why is the offset ? What is wrong?

I also realise that placement means placing the nw corner of the widget.

This sample program can let you select the tip to play with, by clicking on the other tip, to swap to it.

So, you can see, by selecting either tip shape, the behaviour is the same.

import tkinter as tk

def changetip(a):            # change cursor tip, arg a is not used
    global tipType
    if tipType=="red" : tipType="yellow"
    else: tipType="red"

def where(posn):                       #cursor tiop movement and colour change
   cx=posn.x_root-w.winfo_x()
   cy=posn.y_root-w.winfo_y()
   if tipType=="red":
       tipC.place(x=cx, y=cy)
       tipL.place(x=300,y=300)
   else:
       tipC.place(x=400, y=400)
       tipL.place(x=cx,y=cy)

w=tk.Tk()
w.geometry("500x500+100+100")
w.bind("<Motion>",where)        #track mouse movement

tipType="red"           # red is the canvas circle, yellow is label

# Make a cursor tip using a circle on canvas
tip_rad=10
tipC=tk.Canvas(w,width=tip_rad*2,height=tip_rad*2,highlightthickness=0,bg="green")
tip=tk.Canvas.create_oval(tipC,tip_rad/2,tip_rad/2,tip_rad/2*3,tip_rad/2*3, width=0, fill="red")
tipC.bind("<1>",changetip)

# Make a cursor tip using a label
tip_size=1
tipL=tk.Label(w,width=tip_size, height=tip_size,text="x",bg="yellow")
tipL.bind("<1>",changetip)

w.mainloop()

Upvotes: 2

Views: 3620

Answers (1)

Paul Cornelius
Paul Cornelius

Reputation: 10906

You should ignore the event object (posn) and work only with pixel positions that are relative to the main widget w. Change the first two lines of where as follows:

def where(posn):
   cx=w.winfo_pointerx() - w.winfo_rootx()
   cy=w.winfo_pointery() - w.winfo_rooty()

Upvotes: 2

Related Questions