我正在尝试使用圆在Tkinter中为一个简单的太阳系建模,并在画布中四处移动。但是,我一直在努力寻找一种使它们动起来的方法。我环顾四周,发现该move功能与after创建动画循环结合在一起。我尝试使用参数来烦躁,以改变y偏移量并在弯曲路径中创建运动,但是在尝试递归或while循环执行时却失败了。这是我到目前为止的代码:
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()
这里显示了一种使用tkinterafter方法更新对象和关联的画布oval对象的位置的方法。它使用生成器函数沿圆形路径计算坐标,该圆形路径表示Celestial实例之一(名为planet_obj1)的轨道。
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()
这是运行的样子: