【问题标题】:Animating an object to move in a circular path in Tkinter在 Tkinter 中动画对象以在圆形路径中移动
【发布时间】:2017-06-28 23:58:12
【问题描述】:

我正在尝试在 Tkinter 中使用圆圈模拟一个简单的太阳系,并在画布中移动它们。但是,我一直在努力寻找一种方法来为它们设置动画。我环顾四周,发现 move 函数与 after 结合起来创建了一个动画循环。我尝试使用参数来改变y 偏移量并在弯曲路径中创建运动,但是在尝试递归或使用while 循环时失败了。这是我到目前为止的代码:

import tkinter

class celestial:
    def __init__(self, x0, y0, x1, y1):
        self.x0 = x0
        self.y0 = y0
        self.x1 = x1
        self.y1 = y1

sol_obj = celestial(200, 250, 250, 200)
sx0 = getattr(sol_obj, 'x0')
sy0 = getattr(sol_obj, 'y0')
sx1 = getattr(sol_obj, 'x1')
sy1 = getattr(sol_obj, 'y1')
coord_sol = sx0, sy0, sx1, sy1

top = tkinter.Tk()

c = tkinter.Canvas(top, bg='black', height=500, width=500)
c.pack()

sol = c.create_oval(coord_sol, fill='black', outline='white')

top.mainloop()

【问题讨论】:

    标签: python animation tkinter tkinter-canvas


    【解决方案1】:

    这里展示了一种使用 tkinter after 方法来更新对象的位置和关联的画布oval 对象的位置的方法。它使用生成器函数来计算代表Celestial 实例之一(名为planet_obj1)的轨道的圆形路径上的坐标。

    import math
    try:
        import tkinter as tk
    except ImportError:
        import Tkinter as tk  # Python 2
    
    DELAY = 100
    CIRCULAR_PATH_INCR = 10
    
    sin = lambda degs: math.sin(math.radians(degs))
    cos = lambda degs: math.cos(math.radians(degs))
    
    class Celestial(object):
        # Constants
        COS_0, COS_180 = cos(0), cos(180)
        SIN_90, SIN_270 = sin(90), sin(270)
    
        def __init__(self, x, y, radius):
            self.x, self.y = x, y
            self.radius = radius
    
        def bounds(self):
            """ Return coords of rectangle surrounding circlular object. """
            return (self.x + self.radius*self.COS_0,   self.y + self.radius*self.SIN_270,
                    self.x + self.radius*self.COS_180, self.y + self.radius*self.SIN_90)
    
    def circular_path(x, y, radius, delta_ang, start_ang=0):
        """ Endlessly generate coords of a circular path every delta angle degrees. """
        ang = start_ang % 360
        while True:
            yield x + radius*cos(ang), y + radius*sin(ang)
            ang = (ang+delta_ang) % 360
    
    def update_position(canvas, id, celestial_obj, path_iter):
        celestial_obj.x, celestial_obj.y = next(path_iter)  # iterate path and set new position
        # update the position of the corresponding canvas obj
        x0, y0, x1, y1 = canvas.coords(id)  # coordinates of canvas oval object
        oldx, oldy = (x0+x1) // 2, (y0+y1) // 2  # current center point
        dx, dy = celestial_obj.x - oldx, celestial_obj.y - oldy  # amount of movement
        canvas.move(id, dx, dy)  # move canvas oval object that much
        # repeat after delay
        canvas.after(DELAY, update_position, canvas, id, celestial_obj, path_iter)
    
    top = tk.Tk()
    top.title('Circular Path')
    
    canvas = tk.Canvas(top, bg='black', height=500, width=500)
    canvas.pack()
    
    sol_obj = Celestial(250, 250, 25)
    planet_obj1 = Celestial(250+100, 250, 15)
    sol = canvas.create_oval(sol_obj.bounds(), fill='yellow', width=0)
    planet1 = canvas.create_oval(planet_obj1.bounds(), fill='blue', width=0)
    
    orbital_radius = math.hypot(sol_obj.x - planet_obj1.x, sol_obj.y - planet_obj1.y)
    path_iter = circular_path(sol_obj.x, sol_obj.y, orbital_radius, CIRCULAR_PATH_INCR)
    next(path_iter)  # prime generator
    
    top.after(DELAY, update_position, canvas, planet1, planet_obj1, path_iter)
    top.mainloop()
    

    这是运行的样子:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-28
      • 2017-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-30
      相关资源
      最近更新 更多