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