在自定义像素网格上的画布上移动矩形

时间:2018-11-22 19:44:50

标签: python canvas tkinter label

我写了这段代码来练习,它在按下鼠标左键的同时移动了标签:

def motion(self, event):
    delta_x = event.x - self._drag_data["x"]
    delta_y = event.y - self._drag_data["y"]

    self.canvas.move(self._drag_data["item"], delta_x, delta_y)

    self._drag_data["x"] = event.x
    self._drag_data["y"] = event.y

接下来,我尝试将标签移动到已定义的5个像素的网格上。因此,将标签直接“快照”在一起更加容易。

我该怎么做?有没有办法仅每5个像素移动一次标签?因此,每5个像素,标签就会再次跳到光标下方。

以下是我提取函数的示例:

import tkinter as tk

class Example(tk.Frame):

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)

        self.canvas = tk.Canvas(width=400, height=400)
        self.canvas.pack(fill="both", expand=True)

        self._drag_data = {"x": 0, "y": 0, "item": None}

        self._create_token((100, 100), "white")

        self.canvas.tag_bind("token", "<ButtonPress-1>", self.on_token_press)
        self.canvas.tag_bind("token", "<ButtonRelease-1>", self.on_token_release)
        self.canvas.tag_bind("token", "<B1-Motion>", self.on_token_motion)

    def _create_token(self, coord, color):
        (x,y) = coord
        self.canvas.create_oval(x-25, y-25, x+25, y+25, outline=color, fill=color, tags="token")

    def on_token_press(self, event):
        self._drag_data["item"] = self.canvas.find_closest(event.x, event.y)[0]
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y

    def on_token_release(self, event):
        self._drag_data["item"] = None
        self._drag_data["x"] = 0
        self._drag_data["y"] = 0

    def on_token_motion(self, event):
        delta_x = event.x - self._drag_data["x"]
        delta_y = event.y - self._drag_data["y"]
        self.canvas.move(self._drag_data["item"], delta_x, delta_y)
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y

if __name__ == "__main__":
    root = tk.Tk()
    Example(root).pack(fill="both", expand=True)
    root.mainloop()

2 个答案:

答案 0 :(得分:2)

在这里,我们将x和y的增量设置为5,然后检查鼠标位置是否在项目的后面/下方,如果是x或y乘以-1,则增量为负值,因此我们的项目将向我们的鼠标。

def motion(self, event):
    delta_x = 0
    delta_y = 0
    step = 5

    if abs(event.x - self._drag_data["x"]) >= step:
        delta_x = step
    if abs(event.y - self._drag_data["y"]) >= step:
        delta_y = step

    if event.x < self._drag_data["x"]:
        delta_x *= -1
    if event.y < self._drag_data["y"]:
        delta_y *= -1

    self.canvas.move(self._drag_data["item"], delta_x, delta_y)

    if delta_x != 0:
        self._drag_data["x"] = event.x
    if delta_y != 0:
        self._drag_data["y"] = event.y

答案 1 :(得分:0)

您可以简单地将delta_xdelta_y舍入为步长的最接近倍数:

def on_token_motion(self, event):
    step = 20

    # Calculate drag distance
    delta_x = event.x - self._drag_data["x"]
    delta_y = event.y - self._drag_data["y"]

    # Round to nearest multiple of step size
    delta_x = int(step * round(float(delta_x)/step))
    delta_y = int(step * round(float(delta_y)/step))

    # Move the object
    self.canvas.move(self._drag_data["item"], delta_x, delta_y)

    # Update _drag_data to the new position
    self._drag_data["x"] = self._drag_data["x"] + delta_x
    self._drag_data["y"] = self._drag_data["y"] + delta_y

请注意,我还更改了_drag_data更新。对象的新位置不再等于event.x,因为我们捕捉到了网格。因此,我们必须将其更新为self._drag_data["x"] + delta_x,这是旧头寸加上移动的金额。