【问题标题】:Prevent zoomed tkinter canvas objects from moving/changing coordinates防止缩放的 tkinter 画布对象移动/更改坐标
【发布时间】:2025-11-30 00:15:01
【问题描述】:

我正在使用 tkinter 构建一个 GUI 应用程序,该应用程序需要一个用于建模的 CAD 界面,因此我使用了 tkinter 画布小部件。

我基于this thread 实现了使用鼠标移动和缩放画布的方法。我遇到的问题是缩放画布会改变其上对象的坐标(有时坐标从正变为负)。所以如果我在画布上绘制矩形;

self.canvas.create_rectangle(0, 5, 75, 100, outline="black", fill="blue") self.canvas.create_text(100,125, anchor="nw", text="Click and drag to move the canvas\nScroll to zoom.")

然后缩放或移动和缩放画布,并使用;绘制另一个矩形;

self.canvas.create_rectangle(75, 5, 200, 100, outline="black", fill="red")

我希望看到这样的东西;

但我得到了这个;

有没有办法在 tkinter 中解决这个问题?

编辑

我已经用 Bryan 的回答更新了我的代码。我能够在self.scale 属性中跟踪比例因子,但偏移量(在self.offset 属性中跟踪)仍然是错误的。我无法计算重复缩放的累积偏移量。新矩形正确缩放(大小),但偏移/位置仍然关闭。

这是我当前的代码;

import Tkinter as tk

class CAD(tk.Frame):
    def __init__(self, root):
        tk.Frame.__init__(self, root)

        self.scale = 1
        self.offset = [0, 0]
        self.current_scale = [self.offset[0], self.offset[1], self.scale, self.scale]

        self.canvas = tk.Canvas(self, width=400, height=350, background="bisque")
        self.canvas.pack()

        #Plot on the canvas
        self.rect = self.canvas.create_rectangle(0, 5, 75, 100, outline="black", fill="blue")
        self.canvas.create_text(100,125, anchor="nw", text="""
            Left click and drag to move the canvas
            Scroll to zoom
            Right click to draw rectangle""")

        # Mouse bindings to the canvas
        self.canvas.bind("<ButtonPress-1>", self.move_start)
        self.canvas.bind("<B1-Motion>", self.move_move)
        self.bind_all("<MouseWheel>", self.zoom)
        self.canvas.bind("<ButtonPress-3>", self.draw)

    # move
    def move_start(self, event):
        self.canvas.scan_mark(event.x, event.y)
    def move_move(self, event):
        self.canvas.scan_dragto(event.x, event.y, gain=1)

    # zoom
    def zoom(self, event):
        true_x = self.canvas.canvasx(event.x)
        true_y = self.canvas.canvasy(event.y)
        if (event.delta > 0):
            sc = 1.1
        elif (event.delta < 0):
            sc = 0.9
        self.canvas.scale("all", true_x, true_y, sc, sc)
        self.scale *= sc

        self.offset = [sum(x) for x in zip(self.offset, [true_x, true_y])]
        self.current_scale = [self.offset[0], self.offset[1], self.scale, self.scale]

    def draw(self, event):
        new_item = self.canvas.create_rectangle(75, 5, 200, 100, outline="black", fill="red")
        self.canvas.scale(new_item, *self.current_scale)


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

结束编辑

【问题讨论】:

  • 您找到解决问题的方法了吗?我也遇到过类似的问题。
  • 我没有找到解决方案@Manish

标签: python canvas tkinter


【解决方案1】:

陈述您的问题的一种方法是:

  • 我创建了一个对象
  • 我对对象应用了变换
  • 我创建了一个新对象没有进行转换
  • 对象未按预期对齐

要使对象对齐,您需要根据当前的一组转换来转换任何新项目的坐标。

假设您知道当前的比例因子是多少,您可以将比例应用于您创建的任何新项目。

例如,以下代码会产生您在问题中描述的结果,其中两个矩形对齐,即使第二个矩形是在第一个矩形缩放后创建的:

import tkinter as tk

root = tk.Tk()
canvas = tk.Canvas(root, width=400, height=400, background="bisque")
canvas.pack(fill="both", expand=True)

# start with one rectangle
canvas.create_rectangle(0, 5, 75, 100, outline="black", fill="blue")

# scale it, and save the scale
current_scale = (0, 0, 1.5, 1.5)
canvas.scale("all", *current_scale)

# add a new item, and apply the same scale to it
new_item = canvas.create_rectangle(75, 5, 200, 100, outline="black", fill="red")
canvas.scale(new_item, *current_scale)

root.mainloop()

【讨论】:

  • 我已经用你的答案和当前代码更新了问题,但在计算累积偏移量时仍然存在问题。