首页 > 解决方案 > 如何单击并拖动已插入 tkinter 画布上另一个图像顶部的图像

问题描述

我在 tkinter 画布上有一张厨房桌子的图像。前景对象图像(例如,杯子)被插入到桌子图像的顶部。杯子图像具有 alpha 通道以删除其局部背景,因此杯子似乎坐在桌子上。背景图像和前景图像都以标准方式添加到画布中,使用:

canvas.create_image()

上面描述的一切都有效。

目标是:当鼠标悬停在杯子上时,在杯子图像周围放置一个圆圈(这样用户就知道可以拾取物品),然后允许用户单击杯子图像并将其拖动到桌子上的新位置(即画布)。

我尝试将鼠标按下事件绑定到圆圈(参见下面的代码)。为此,我遵循下面链接的一般示例;但是,在我的情况下它不起作用。

单击矩形时的python tkinter画布

下面是重现问题的简化代码。代码将圆形放在画布上并定义了四个相关的回调。三是必绕;一个画布。期望是所有四个回调都应该工作。现实是通过 tags="click_zone" 绑定到圆圈的回调不起作用,而绑定到画布的回调起作用。

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

最终,我想将拾取鼠标事件直接绑定到图像而不是圆圈;但是,我从未在网上找到有人成功将鼠标事件绑定到画布上的图像的示例。

标签: pythontkintercanvas

解决方案


至少部分问题是因为你这样做了tags="click zone"。标签应该是列表或元组,而不是字符串。由于 tcl 解释空格的方式,底层 tcl/tk 画布认为您正在应用两个标签:“click”和“zone”。因此,您对“点击区域”的绑定将不起作用。

另一个问题是画布对象绑定仅适用于对象本身。对于一个圆圈,这意味着<ButtonPress-1>只有单击圆圈的轮廓而不是单击圆圈内部时才会起作用。如果您添加填充颜色,您将能够单击圆圈上的任意位置。

至于绑定到图像,其工作方式与绑定到任何其他画布对象完全相同。这个关于拖放的类似问题的答案有一个完整的工作解决方案:https ://stackoverflow.com/a/6789351/7432


推荐阅读