-1

I have image of a kitchen table on tkinter canvas. A foreground object image (e.g., a cup) is inserted on top of table image. Cup image has alpha channel to remove its local background so cup appears to be sitting on table. Both background image and foreground image were added to canvas in standard way using:

canvas.create_image()

Everything described above works.

Goal is this: place circle around cup image when mouse is over cup (so user knows item can be picked up) then allow user to click on cup image and drag it to new location on table (i.e., canvas).

I tried binding mouse down event to circle (see code below). For this, I followed general example linked below; however, it didn't work in my case.

python tkinter canvas when rectangle clicked

Below is simplified code to reproduce problem. Code puts circle on canvas and defines four related callbacks. Three are bound to circle; one to canvas. Expectation is that all four callbacks should work. Reality is callbacks bound to circle via tags="click_zone" don't work while callback bound to canvas works.

import cv2
from tkinter import Tk, Canvas
from PIL import ImageTk, Image
import time


class ClickZone:
    def __init__(self, _canvas, _bbox):
        self.click_zone = _canvas.create_oval(_bbox, tags=("click zone"))
        _canvas.tag_bind("click zone", '<Enter>', self.on_enter)
        _canvas.tag_bind("click zone", '<Leave>', self.on_leave)
        _canvas.tag_bind("click zone", '<ButtonPress-1>', self.pick_up_object)
        _canvas.bind("<ButtonRelease-1>", self.drop_object)

    def drop_object(self, event):
        print("Drop")

    def pick_up_object(self, event):
        print("Pick up")

    def on_enter(self, event):
        print("Enter")

    def on_leave(self, event):
        print("Leave")


root = Tk()
canvas = Canvas(root, width=800, height=600)
canvas.grid()

# Center of inserted object image
x_center_fg_object = 400
y_center_fg_object = 300

# Diameter of smallest circle fully enclosing inserted object image
fg_object_click_zone_radius = 250

# Bounding box around click zone circle
x0 = x_center_fg_object - fg_object_click_zone_radius
y0 = y_center_fg_object - fg_object_click_zone_radius
x1 = x_center_fg_object + fg_object_click_zone_radius
y1 = y_center_fg_object + fg_object_click_zone_radius
bbox = (x0, y0, x1, y1)

fg_object_click_zone = ClickZone(canvas, bbox)

root.mainloop()

Ultimately, I would like to bind pick-up mouse event directly to image instead of to the circle; however, I never found an example online where someone successfully binds mouse event to image on canvas.

Aether
  • 85
  • 8
  • _"Never found an example online where someone successfully binds mouse event to image on canvas, so . . ."_ - that's surprising, you bind to an image exactly the same way you bind to any other canvas object. – Bryan Oakley Jul 23 '20 at 21:40
  • This answer works with an image exactly the same as with an oval: https://stackoverflow.com/a/6789351/7432 – Bryan Oakley Jul 23 '20 at 21:44
  • @Bryan Oakly -- I can use the solution you linked above (thanks) but am still wondering why my code doesn't work. Bindings between oval and mouse seem equal in both cases yet linked code works while my code doesn't. – Aether Jul 23 '20 at 22:37
  • I don't know. Your example won't run as posted. – Bryan Oakley Jul 23 '20 at 22:44
  • I posted code to reproduce problem. – Aether Jul 23 '20 at 23:11
  • One of the problems with this site is we don’t get notifications when a downvoted question is updated, so downvotes don’t always get reversed. – Bryan Oakley Jul 25 '20 at 02:55

1 Answers1

1

At least part of the problem is because you do tags="click zone". tags should be a list or tuple, not a string. Because of how tcl interprets spaces, the underlying tcl/tk canvas thinks you're applying two tags: "click" and "zone". Therefore your binding on "click zone" won't work.

Another problem is that canvas object bindings only work on the object itself. For a circle, that means that <ButtonPress-1> will only work if you click on the outline of the circle and not if you click inside the circle. If you add a fill color, you'll be able to click anywhere on the circle.

As for binding to an image, that works exactly the same as binding to any other canvas objects. This answer to a similar question about drag and drop has a complete working solution: https://stackoverflow.com/a/6789351/7432

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thanks, your answer addresses full issue. Bit about clicking outline versus clicking inside circle particularly helpful in my case. – Aether Jul 25 '20 at 00:22