防止缩放的Tkinter画布对象移动/更改坐标 [英] Prevent zoomed tkinter canvas objects from moving/changing coordinates

查看:55
本文介绍了防止缩放的Tkinter画布对象移动/更改坐标的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用tkinter构建一个GUI应用程序,并且该应用程序需要一个CAD界面进行建模,因此我为此使用了tkinter canvas小部件.

我基于此线程.我遇到的问题是缩放画布会更改其上对象的坐标(有时坐标会从正变为负).因此,如果我使用;在画布上绘制矩形

self.canvas.create_rectangle(0,5,75,100,outline ="black",fill ="blue") self.canvas.create_text(100,125,anchor ="nw",text =单击并拖动以移动画布\ n滚动以缩放.")

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

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

我希望看到这样的东西

但是我得到了这个

反正在tkinter上有解决此问题的方法吗?

编辑

我已经用布莱恩的答案更新了代码.我能够在 self.scale 属性中跟踪比例因子,但是偏移量(在 self.offset 属性中跟踪)仍然是错误的.我无法通过重复缩放来计算累积偏移量.新矩形可以正确缩放(明智地调整大小),但偏移/位置仍处于关闭状态.

这是我当前的代码;

 将Tkinter导入为tkCAD(tk.Frame)类:def __init __(self,root):tk.Frame .__ init __(self,root)self.scale = 1self.offset = [0,0]self.current_scale = [self.offset [0],self.offset [1],self.scale,self.scale]self.canvas = tk.Canvas(自我,宽度= 400,高度= 350,背景="bisque")self.canvas.pack()#在画布上绘制self.rect = self.canvas.create_rectangle(0,5,75,100,outline ="black",fill ="blue")self.canvas.create_text(100,125,anchor ="nw",text ="左键单击并拖动以移动画布滚动缩放右键单击以绘制矩形")#鼠标绑定到画布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)# 移动def move_start(自我,事件):self.canvas.scan_mark(event.x,event.y)def move_move(自我,事件):self.canvas.scan_dragto(event.x,event.y,gain = 1)# 飞涨def zoom(自我,事件):true_x = self.canvas.canvasx(event.x)true_y = self.canvas.canvasy(event.y)如果(event.delta> 0):sc = 1.1省略号(event.delta< 0):sc = 0.9self.canvas.scale("all",true_x,true_y,sc,sc)self.scale * = scself.offset = [zip中x的sum(x)(self.offset,[true_x,true_y])]self.current_scale = [self.offset [0],self.offset [1],self.scale,self.scale]def draw(自我,事件):new_item = self.canvas.create_rectangle(75,5,200,100,outline ="black",fill ="red")self.canvas.scale(new_item,* self.current_scale)如果__name__ =="__main__":根= tk.Tk()CAD(root).pack(fill ="both",expand = True)root.mainloop() 

END EDIT

解决方案

陈述问题的一种方法是:

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

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

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

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

 将tkinter导入为tk根= tk.Tk()canvas = tk.Canvas(root,width = 400,height = 400,background ="bisque")canvas.pack(fill ="both",expand = True)#从一个矩形开始canvas.create_rectangle(0,5,75,100,outline =黑色",fill =蓝色")#缩放并保存比例current_scale =(0,0,1.5,1.5)canvas.scale("all",* current_scale)#添加一个新项目,并对其应用相同的比例new_item = canvas.create_rectangle(75,5,200,100,outline ="black",fill ="red")canvas.scale(new_item,* current_scale)root.mainloop() 

I'm building a GUI application using tkinter, and the app needs a CAD interface for modelling so I used the tkinter canvas widget for that.

I implemented methods to move and zoom the canvas with a mouse based on this thread. The problem I'm having is that zooming the canvas changes the coordinates of objects on it (sometimes the coordinates change from positive to negative). So if I plot rectangle on the canvas using;

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.")

Then zoom or move and zoom the canvas, and plot another rectangle using;

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

I expected to see something like this;

But I get this instead;

Is there anyway to fix this in tkinter?

EDIT

I've updated my code with Bryan's answer. I was able to track the scale factor in the self.scale attribute but the offset (tracked in the self.offset attribute) is still wrong. I'm not able to calculate the cumulative offset from repeated zooming. New rectangles scale properly (size wise) but the offset/location is still off.

Here is my current code;

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

END EDIT

解决方案

One way to state your problem is this:

  • I created an object
  • I applied a transformation on the object
  • I created a new object without the transformation
  • the objects are not aligned as I expect

To get the objects to align you need to transform the coordinates of any new items based on the current set of transformations.

Assuming you know what the current scale factor is, you can just apply the scaling to any new items you create.

For example, the following code yields a result like you describe in the question, where the two rectangles are aligned even though the second one was created after the first one was scaled:

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

这篇关于防止缩放的Tkinter画布对象移动/更改坐标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆