首页 > 解决方案 > 如何通过角落拖动画布上的对象?以及如何将对象分开一次?

问题描述

我正在尝试创建一个简单的程序,您可以在其中通过拖动来在 tkinter 的画布上移动多个对象。首先,我从 2 个正方形开始。但是,我面临两个问题:

  1. 每当我单击对象时,它都会以鼠标指针为中心(指针始终位于正方形的中间)。如何通过单击位置拖动对象(例如按角拖动)?

  2. 一旦我用一个方格穿过另一个方格,第二个方格就会停留在顶部,不能再分开了。对象具有相同的大小。

有什么简单的解决方案吗?感谢您提供任何帮助或建议。

我的代码:

import tkinter
c = tkinter.Canvas(width = 400, height = 300)
c.pack()

d = 25  #size of square
x, x2 = 100, 200
y, y2 = 100, 200

rect = c.create_rectangle(x-d, y-d, x+d, y+d, fill = 'blue')     #first square
rect2 = c.create_rectangle(x2-d, y2-d, x2+d, y2+d, fill = 'red')    #second square

def drag(event): #drag by holding mouse button 1
    global x, y, x2, y2, xt, yt, x2t, y2t
    xt, yt = event.x, event.y   #1st square movement coords
    x2t, y2t = event.x, event.y #2nd square movement coords
    if xt in range(x-d, x+d):
        if yt in range(y-d, y+d):
            c.coords(rect, xt-d, yt-d, xt+d, yt+d)  #coords update of 1st square
            x, y = xt, yt
    if x2t in range(x2-d, x2+d):
        if y2t in range(y2-d, y2+d):
            c.coords(rect2, x2t-d, y2t-d, x2t+d, y2t+d) #coords update of 2nd square
            x2, y2 = x2t, y2t

c.bind('<B1-Motion>', drag)

tkinter.mainloop()

标签: python-3.xtkinterbindtkinter-canvas

解决方案


有两个问题:

1-要通过角捕获对象,您需要将对象位置偏移其边界框尺寸的一半。(请参阅通过右下角捕获对象的示例;您可以通过更改所用偏移的符号来更改角。)

2-为了在拖动对象时区分对象,您需要在已捕获对象时“停用”回调。这个例子展示了如何做我认为必要的家务。(但可能有更好的方法,内置 tkinter、IDK)

import tkinter


captured = None


def capture(event):
    global captured
    print('captured')
    if captured is None:
        captured = event.widget.find_closest(event.x, event.y)


def release(event):
    global captured
    print('released')
    captured = None


def drag(event):   # drag by holding mouse button 1
    global captured
    if captured is None:
        print(f'captured {event.widget.find_closest(event.x, event.y)}')
        captured = event.widget.find_closest(event.x, event.y)
        print(f'captured: {captured}')
    else:
        x0, y0, x1, y1 = c.bbox(captured)
        xt, yt = event.x + (x0 - x1) // 2, event.y + (y0 - y1) // 2      # 1st square movement coords
        c.coords(captured, xt-d, yt-d, xt+d, yt+d)        # coords update of 1st square


if __name__ == '__main__':

    c = tkinter.Canvas(width = 400, height = 300)
    c.pack()

    d = 25   # size of square
    x, x2 = 100, 200
    y, y2 = 100, 200

    rect1 = c.create_rectangle(x-d, y-d, x+d, y+d, fill='blue', tags='r1')        # first square
    rect2 = c.create_rectangle(x2-d, y2-d, x2+d, y2+d, fill='red', tags='r2')    # second square

    c.bind('<Button-1>', capture)
    c.bind('<ButtonRelease-1>', release)
    c.bind('<B1-Motion>', drag)

    tkinter.mainloop()

推荐阅读