Python Tkinter:如何让画布每帧更新多边形坐标? [解决了]

Posted

技术标签:

【中文标题】Python Tkinter:如何让画布每帧更新多边形坐标? [解决了]【英文标题】:Python Tkinter : How do I get the canvas to update polygon coordinates every frame? [solved] 【发布时间】:2022-01-21 15:44:33 【问题描述】:

我正在做一个玩具项目来学习 tkinter 的基础知识。

我在np.array 对象中有一个具有位置和速度的 Drone 类,它会在每个增量时自我更新。 位置是介于 0 和 1 之间的浮点数,然后乘以高度/宽度。

我现在想看到这架无人机在屏幕上移动,所以我使用了window.after()window.update() 方法。

这是我写的代码:

import tkinter as tk
import numpy as np

def update_drone(canv, drone):
    # update the coords of all the polygon objects with new position (scaled to screen dimensions)
    canv.coords(canv.find_withtag("drone"), *([WIDTH, HEIGHT] * drone.position))


def game_loop(window, canvas, dr):
    delta = 0.01

    # function which updates drone's attributes
    dr.update(delta)
    
    # built in sleep
    sleep(delta)

    #update drone function from above
    update_drone(canvas, dr)

   
    canvas.pack()

    # if the drone isnt below the screen, call the game loop next delta
    if dr.position[1] < 1:
        window.after(int(delta * 1000), game_loop, window, canvas, dr)


if __name__ == "__main__":
    # set up window
    window = tk.Tk()
    window.maxsize(WIDTH, HEIGHT)
    window.minsize(WIDTH, HEIGHT)
    window.configure(bg="black")


    # height and width are global variables i define
    canvas = tk.Canvas(window, bg="black", height=HEIGHT, width=WIDTH)

    # create Drone object
    dr = Drone()
    # call draw drone function which is defined below
    draw_drone(canvas, dr)

    window.after(0, game_loop, window, canvas, dr)
    # main loop
    window.mainloop()

我上面调用的draw_drone 函数初始化了两个多边形:


def draw_drone(canv: tk.Canvas, drone: Drone) -> None:

    pos_x, pos_y = WIDTH * drone.position[0], HEIGHT * drone.position[1]
    # draw drone body
    size = 20
    canv.create_polygon(
        [
            pos_x - size,
            pos_y - size,
            pos_x - size,
            pos_y + size,
            pos_x + size,
            pos_y + size,
            pos_x + size,
            pos_y - size,
        ],
        outline="white",
        fill="yellow",
        width=3,
        tags="drone",
    )
    canv.create_polygon(
        [
            pos_x,
            pos_y + 0.8 * size,
            pos_x - 0.8 * size,
            pos_y,
            pos_x,
            pos_y - 0.8 * size,
            pos_x + 0.8 * size,
            pos_y,
        ],
        outline="red",
        fill="grey",
        width=8,
        tags="drone",
    )

当我运行上面的代码时,游戏循环被调用(当我打印出无人机位置的值时,它们确实会相应地更新)但画布在第一帧被冻结并且永远不会更新。

如果有人能告诉我问题出在哪里,我将不胜感激!

编辑:

这是我使用的基本无人机类:

class Drone:
    def __init__(self):
        self.position = np.array([0.5, 0.5])
        self.velocity = np.array([0, 0])
        self.forces = np.array([0, 0])

    def update(self, dt):
        self.velocity = dt * (self.forces + np.array([0, 1]))  # forces + gravity
        self.position += self.velocity * dt

【问题讨论】:

Drone 没有定义,你能展示一下这个类的样子吗?还提供一个完整的minimal reproducible example,顺便说一句,您不需要在任何小部件上使用update 方法 @Matiiss 感谢您的回答,我更新了我的帖子。 我找到了解决方案,更新了我最初的帖子 如果你找到了解决方案,你应该写一个答案而不是编辑你的问题 哦,非常感谢,抱歉我对 SO 比较陌生 【参考方案1】:

最后我的错误很简单。我不明白canvas.coords 是如何工作的。我的update_drone 函数的正确代码实际上是:

for t in canvas.find_withtag("drone"):
        canv.coords(t, *([WIDTH, HEIGHT] * drone.position))

而不是

canv.coords(canv.find_withtag("drone"), *([WIDTH, HEIGHT] * drone.position))

这会正确更新坐标。

【讨论】:

以上是关于Python Tkinter:如何让画布每帧更新多边形坐标? [解决了]的主要内容,如果未能解决你的问题,请参考以下文章

Python,Tkinter:如何在可滚动画布上获取坐标

Python:在使用多处理时更新 Tkinter

python tkinter怎么让顶层界面有scrollbar

Python 中 Tkinter 画布上 .jpg 图像的滚动条

如何设置 Python tkinter 画布元素的 z 索引?

Python Tkinter 在 GUI 中嵌入 Matplotlib