防止缩放的tkinter画布对象移动/更改坐标

时间:2017-01-03 20:55:57

标签: python canvas tkinter

我正在使用tkinter构建GUI应用程序,应用程序需要一个CAD界面进行建模,所以我使用了tkinter canvas小部件。

我实现了使用基于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")

我希望看到类似的东西;

Expected output image

但我得到了这个;

Actual output

无论如何要在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()

结束编辑

1 个答案:

答案 0 :(得分:2)

说明问题的一种方法是:

  • 我创建了一个对象
  • 我在对象上应用了转换
  • 我创建了一个没有转换的新对象
  • 对象没有像我期望的那样对齐

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

假设您知道当前比例因子是什么,您只需将缩放应用于您创建的任何新项目。

例如,以下代码产生的结果就像您在问题中描述的那样,即使第二个矩形在第一个缩放后创建了第二个矩形,它们也会对齐:

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