Tkinter将矩形小部件下方的小部件绑定到鼠标事件

时间:2016-09-01 03:19:55

标签: python user-interface canvas tkinter tkinter-canvas

我希望我能正确解释问题。 我下面的例子能够移动画布上定义的两个图像。问题是我想要一个矩形,也在画布上定义,在图像的顶部。当我使用.tag_raise执行此操作时,由鼠标拖动触发的事件由矩形触发,而不是图像。

我尝试使用bing_class但是没有用。我试图为矩形定义一个单独的画布,但它必须覆盖主画布而且卡住了。

如何将矩形保持在顶部但将图像绑定到鼠标拖动事件?

import Tkinter as tk # for Python2
import PIL.Image, PIL.ImageTk

win = tk.Tk()
canvas = tk.Canvas(win, height = 500, width = 500)

#Create a rectangle with stipples on top of the images
rectangle = canvas.create_rectangle(0, 0, 400, 300, fill = "gray", stipple = "gray12")

#Create two images
SPRITE = PIL.Image.open("image.jpg")
imagePIL = SPRITE.resize((100, 100))
imagePI = PIL.ImageTk.PhotoImage(imagePIL)
image1 = canvas.create_image(100, 100, image = imagePI, tags = "image")
image2 = canvas.create_image(200, 200, image = imagePI, tags = "image")

#Callback
# Here I select image1 or image2 depending on where I click, and
# drag them on the canvas. The problem is when I put the rectangle
# on top using tag_raise (see below).
def callback(event):
    id = canvas.find_withtag(tk.CURRENT)
    canvas.coords(id, (event.x, event.y))

#Binding
canvas.bind("<B1-Motion>", callback)
#Place the rectangle on top of all
canvas.pack()

# This is the problem. I want to have the rectangle on top and be able to use the callback
#canvas.tag_raise(rectangle)

canvas.mainloop()

解决方案:我使用以下代码增强了Nehal的答案。他的回答有一个小故障,可以切换图像。在我的增强中,我通过为每个图像存储一个锁来解决它,以便在拖动画布上的图像时拖动相同的图像。当我搬家时image1 over image2我注意到image1没有完全移过image2,这对我来说很好。

import Tkinter as tk # for Python2
import PIL.Image, PIL.ImageTk

win = tk.Tk()
canvas = tk.Canvas(win, height = 500, width = 500)

#Create a rectangle with stipples on top of the images
rectangle = canvas.create_rectangle(0, 0, 400, 300, fill = "gray", stipple = "gray12")

#Create two images
SPRITE = PIL.Image.open("image.jpg")
imagePIL = SPRITE.resize((100, 100))
imagePI = PIL.ImageTk.PhotoImage(imagePIL)
image1 = canvas.create_image(100, 100, image = imagePI, tags = "image")
image2 = canvas.create_image(200, 200, image = imagePI, tags = "image")
images = [image1, image2]
locks = [True, True]

def getImage(x, y):
    for image in images:
        curr_x, curr_y = canvas.coords(image)
        x1 = curr_x - imagePI.width()/2
        x2 = curr_x + imagePI.width()/2
        y1 = curr_y - imagePI.height()/2
        y2 = curr_y + imagePI.height()/2
        if (x1 <= x <= x2) and (y1 <= y <= y2):
            return image
#Callback
# Here I select image1 or image2 depending on where I click, and
# drag them on the canvas.
def callback(event):
    id  = getImage(event.x, event.y)
    if id:
        if locks[images.index(id)] is False: #Hold on to the image on which I originally clicked
            canvas.coords(id, (event.x, event.y))

def mouseClick(event):
    id  = getImage(event.x, event.y)
    if id:
        locks[images.index(id)] = False
    print(locks)

def mouseRelease(event):
    id  = getImage(event.x, event.y)
    if id:
        locks[images.index(id)] = True
    print(locks)
#Binding
canvas.bind("<ButtonPress-1>", mouseClick)      #unlock the image to move it
canvas.bind("<ButtonRelease-1>", mouseRelease)  #lock the image
canvas.bind("<B1-Motion>", callback)
#Place the rectangle on top of all
canvas.pack()

# This was the original problem
canvas.tag_raise(rectangle)

canvas.mainloop()

1 个答案:

答案 0 :(得分:2)

我不知道tkinter具体的方法,但是,您可以尝试获取最近图像的坐标并使用它们。像这样:

import Tkinter as tk # for Python2
import PIL.Image, PIL.ImageTk

win = tk.Tk()
canvas = tk.Canvas(win, height = 500, width = 500)

#Create a rectangle with stipples on top of the images
rectangle = canvas.create_rectangle(0, 0, 400, 300, fill = "gray", stipple = "gray12")

#Create two images
SPRITE = PIL.Image.open("image.jpg")
imagePIL = SPRITE.resize((100, 100))
imagePI = PIL.ImageTk.PhotoImage(imagePIL)
image1 = canvas.create_image(100, 100, image = imagePI, tags = "image")
image2 = canvas.create_image(200, 200, image = imagePI, tags = "image")
images = [image1, image2]

def getImage(x, y): 
    for image in images:
        curr_x, curr_y = canvas.coords(image)
        x1 = curr_x - imagePI.width()/2
        x2 = curr_x + imagePI.width()/2
        y1 = curr_y - imagePI.height()/2
        y2 = curr_y + imagePI.height()/2
        if (x1 <= x <= x2) and (y1 <= y <= y2):
            return image
#Callback
# Here I select image1 or image2 depending on where I click, and
# drag them on the canvas. The problem is when I put the rectangle
# on top using tag_raise (see below).
def callback(event):
    id  = getImage(event.x, event.y)
    if id: 
        canvas.coords(id, (event.x, event.y))

#Binding
canvas.bind("<B1-Motion>", callback)
#Place the rectangle on top of all
canvas.pack()

# This is the problem. I want to have the rectangle on top and be able to use the callback
canvas.tag_raise(rectangle)

canvas.mainloop()

enter image description here