4

I am developing a small python gui, just for fun and for learning, and I have been trying to change the cursor shape over canvas items.

I know that it is possible to change the cursor shape when hovering over a canvas widget, using the cursor="whatever" option at canvas creation. But I would like to do that for items inside this canvas only.

That makes the item correctly:

self.image_obj = canvas.create_image(
        self.column_coordinate,
        self.row_coordinate,
        image=image
    )

That does not work:

self.image_obj = canvas.create_image(
        self.column_coordinate,
        self.row_coordinate,
        image=image,
        cursor="hand1"
    )

The "cursor" option does not seem to exist for items, is there a way to go around the problem?

2 Answers2

4

The only way to change the cursor is via changing how it presents on the canvas. By checking every time the mouse moves whether it is inside the boundary box of the item you want it to change over you can achieve this effect.

from tkinter import *

canvas = Canvas(width=200,height=200)
canvas.pack()

rec = canvas.create_rectangle(100,0,200,200,fill="red")#example object

def check_hand(e):#runs on mouse motion
    bbox= canvas.bbox(rec)
    if bbox[0] < e.x and bbox[2] > e.x and bbox[1] < e.y and bbox[3] > e.y:#checks whether the mouse is inside the boundrys
        canvas.config(cursor="hand1")
    else:
        canvas.config(cursor="")

canvas.bind("<Motion>",check_hand)#binding to motion
4

Spent some time figuring this out.

Below method works for all shapes using tag_bind() method with Enter and Leave.

import tkinter as tk

main_window = tk.Tk()


def check_hand_enter():
    canvas.config(cursor="hand1")


def check_hand_leave():
    canvas.config(cursor="")


canvas = tk.Canvas(width=200, height=200)
tag_name = "polygon"

canvas.create_polygon((25, 25), (25, 100), (125, 100), (125, 25), outline='black', fill="", tag=tag_name)

canvas.tag_bind(tag_name, "<Enter>", lambda event: check_hand_enter())
canvas.tag_bind(tag_name, "<Leave>", lambda event: check_hand_leave())

canvas.pack()
main_window.mainloop()
  • I think this one is the better between the two answers. The and tags are a lot more readable and probably less computationally expensive than the other answer (although both perform about the same in any real-life context). – TimH Jan 16 '22 at 02:56