tkinter canvas.coords()与canvas.moveto()坐标不同

1 投票
1 回答
56 浏览
提问于 2025-04-14 17:07

我尝试了以下脚本,在一个填满整个窗口的canvas上:

import tkinter as tk
from PIL import Image, ImageTk
from time import *

root = tk.Tk()
root.geometry("500x500")
canvas = tk.Canvas(root)
canvas.pack()

def fill(event):
    canvas.config(width = root.winfo_width(), height = root.winfo_height())
root.bind("<Configure>", fill)

img = Image.open("CO2.png")
imgtk = ImageTk.PhotoImage(img)
item = canvas.create_image(15, 15, image = imgtk)
while True:
    canvas.moveto(item, canvas.coords(item)[0], canvas.coords(item)[1])
    root.update()
    sleep(0.5)

理论上,这个操作应该没什么效果,因为它只是把一个物体移动到它原本的位置。但实际上,这个操作却把图像向正的x和y方向移动了,这意味着通过canvas.coords()获取的坐标有点不准确,和canvas.moveto()的结果不一致。

这是我使用的图像:

这里输入图像描述

这到底是怎么回事呢?

1 个回答

2

这个行为是有说明的,你看到的功能就是这样设计的。
canvas.coords(item) 会返回这个物体现在的位置。
canvas.moveto(item, *coord_list) 会把这个物体放到指定的坐标位置,确保它的左上角在 *coord_list 中给出的坐标的下面和旁边。

你可以对比一下coordsmoveto 的说明。

如果没有指定坐标,这个命令会返回一个列表,列表里的元素是由 tagOrId 指定的物体的坐标。

还有

在画布坐标空间中移动由 tagOrId 指定的物体,使得第一个物体(在显示列表中最底下的那个)左上角的坐标位于 (xPos,yPos) 这个位置。

这段小代码展示了你的体验:

import tkinter as tk

def test(event):
    cnvs.moveto(rect, *cnvs.coords(rect)[0:-2])

root = tk.Tk()
cnvs = tk.Canvas(root, highlightthickness=0)
cnvs.pack()
rect = cnvs.create_rectangle(0,0,50,50, fill='red')
print(cnvs.coords(rect))
root.bind('<1>', test)
root.mainloop()

如果把函数 test 改成下面这样,就能解决问题:

def test(event):
    delta = int(float(cnvs.itemcget(rect, 'width'))/2)
    coords = [coordinate-delta for coordinate in cnvs.coords(rect)[0:-2]]
    cnvs.moveto(rect, *coords)

不过,你还需要根据不同的物体类型和其他坐标属性进行调整。通常情况下,使用 tk 和 tkinter 更新坐标的方法是用 canvas.coords(item, *new_coords)

撰写回答