0

My goal is to draw a tkinter shape at the tip of my mouse in case of some event. When the mouse moves over the widgets of my application, I want the shape to remain visible.

I am struggling to understand how I should approach this, in relation to the Canvas object. In the example underneath I defined a canvas object, and I have an image that moves with the mouse.

But when I hover over the Hello World label, the image is shown below the label. If I create the canvas AFTER I create the label, then the label is not visible. What should I do?

from tkinter import *
from tkinter import ttk
from PIL import Image, ImageTk

# Create an instance of tkinter frame
win = Tk()

# Set the size of the tkinter window
win.geometry("700x350")

# Create a frame with some content
frm = ttk.Frame(win)
frm.grid(row=0,column=0)

# Define a Canvas widget in the frame
canvas = Canvas(frm, width=700, height=350, bg="white")
canvas.grid(row=0,column=0)

# Make a widget over the canvas
ttk.Label(frm, text="Hello World!").grid(column=0, row=0)

# Path to some image
img_path = r"test.jpg"

# Function for getting mouse pos
def get_mouse_pos(event):
    return (event.x_root-win.winfo_rootx(), event.y_root - win.winfo_rooty())

# Define a function to allow the image to move within the canvas
def move(e):
   global image
   mouse = get_mouse_pos(e)
   image = ImageTk.PhotoImage(Image.open(img_path))
   img = canvas.create_image(mouse[0], mouse[1], image=image)

# Bind the move function
win.bind("<Motion>", move)

win.mainloop()

Edit:

I may have found something that works. Instead of positioning the canvas with .grid(), using .place(x=,y=) allows placing the canvas on a specific coordinate. So if I make the canvas really small , then I can just project a small image on the canvas and it remains visible on top of other widgets, given that the canvas is created after the widgets.

I am still in doubt though if this is the best approach. For example I have noticed there is some lag related to framerate, where the mini-canvas is struggling to keep up with the mouse. ALso I would like the canvas to be transparent, but I believe that that is not possible. Any thoughts or further advice on this? Edited code below:

from tkinter import *
from tkinter import ttk
from PIL import Image, ImageTk

# Create an instance of tkinter frame
win = Tk()

# Set the size of the tkinter window
win.geometry("700x350")

# Create a frame with some content
frm = ttk.Frame(win)
frm.grid(row=0,column=0)

# Define a Canvas widget in the frame
# canvas = Canvas(frm, width=700, height=350, bg="white")
# canvas.grid(row=0,column=0)

# Make a widget over the canvas
ttk.Label(frm, text="Hello World!").grid(column=0, row=0)

# New idea: make small canvas and move it with mouse
canvas2 = Canvas(frm, width = 10, height=10, bg='blue')
canvas2.place(x=100,y=100)

# Path to some image
img_path = r"test.jpg"

# Function for getting mouse pos
def get_mouse_pos(event):
    return (event.x_root-win.winfo_rootx(), event.y_root - win.winfo_rooty())

# Define a function to allow the image to move within the canvas
def move(e):
   global image
   mouse = get_mouse_pos(e)
   # image = ImageTk.PhotoImage(Image.open(img_path))
   # img = canvas.create_image(mouse[0], mouse[1], image=image)
   canvas2.place(x=mouse[0], y=mouse[1])

# Bind the move function
win.bind("<Motion>", move)

win.mainloop()
  • you have to put label on canvas using `canvas.create_window(window=your_label,...)` instead of `grid()`. And you have to put it before you put image on this canvas. – furas May 23 '22 at 11:51
  • 1
    See [How to make a tkinter canvas rectangle transparent?](https://stackoverflow.com/a/54645103/355230) – martineau May 23 '22 at 11:55
  • 1
    maybe you should use `label` with `image` instead of `canvas`. – furas May 23 '22 at 12:22

0 Answers0