【问题标题】:Move rectangle on canvas on a custom pixel grid在自定义像素网格上移动画布上的矩形
【发布时间】:2018-11-22 19:44:50
【问题描述】:

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

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

【问题讨论】:

    标签: python canvas tkinter label


    【解决方案1】:

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

    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
    

    【讨论】:

    • 它可以满足我的要求。我只是忘了写它应该与光标同步移动。对不起!我将鼠标移动了 4 个像素,没有任何反应。如果我将它移动 5 个像素,则标签应捕捉到下一个 5 像素网格。
    • 已更新,立即尝试。
    • 现在我有一些奇怪的动作,有时标签会随着鼠标移动但偏离目标。有时什么都不会发生。
    • 你能提供足够的代码来重现这个问题吗?
    • 问题是我们正在更新我们的_drag_data,即使我们实际上并没有移动我们的画布,更新答案并修复了该错误。
    【解决方案2】:

    您可以简单地将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,即旧仓位加上移动量。

    【讨论】:

      猜你喜欢
      • 2016-12-03
      • 2017-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多