Skip to main content
 首页 » 编程设计

超出 Python tkinter Canvas root.after() 最大递归深度

2025年05月04日10langtianya

from tkinter import * 
 
root = Tk() 
canvas = Canvas(root, width=400, height=400, bg="white") 
canvas.pack() 
rect = canvas.create_rectangle(100, 100, 110, 110, fill='blue') 
def move_down(event): 
    canvas.move(rect, 0, 10) 
    root.after(1, move_down(event)) 
root.bind('<Down>', move_down) 
root.mainloop() 

我似乎无法弄清楚如何使 root.after() 工作。我该如何解决这个问题,使矩形继续向下移动?

请您参考如下方法:

简短版本:您不能在传递给 after 的函数上加上括号。

    root.after(1,move_down(event)) 

此行没有将函数 move_down 注册为 after 事件的回调。相反,它会立即调用 move_down,如果您没有进入无限递归,它会将 move_down 的返回值注册为回调。

要解决这个问题,只使用 move_down 而无需实际调用它,并使 event 成为可选变量,因为 after 不会提供一个值。您可能还应该使用大于 1 毫秒的时间,否则您的矩形会在眨眼间从屏幕上消失。

from tkinter import * 
root = Tk() 
canvas = Canvas(root, width=400, height= 400, bg="white") 
canvas.pack() 
rect = canvas.create_rectangle(100, 100, 110, 110, fill='blue') 
def move_down(event=None): 
    canvas.move(rect, 0, 10) 
    root.after(100,move_down) 
root.bind('<Enter>', move_down) #or whatever you're binding it to 
root.mainloop() 

额外信息:如果您要问“好吧,现在我如何让矩形在我松开按键时停止移动?以及如何在我按下其他箭头键时使它沿彼此的方向移动?”这需要更复杂的设计。您需要注册到 root.after 的函数来根据矩形的速度移动可变数量的像素,矩形的速度会根据独立发生的关键事件而改变。实现示例:

from tkinter import * 
root = Tk() 
canvas = Canvas(root, width=400, height= 400, bg="white") 
canvas.pack() 
rect = canvas.create_rectangle(100, 100, 110, 110, fill='blue') 
x_velocity = 0 
y_velocity = 0 
 
keys_being_held_down = set() 
key_accelerations = { 
    "Up": (0, -10), 
    "Down": (0, 10), 
    "Left": (-10, 0), 
    "Right": (10, 0) 
} 
 
def key_pressed(event): 
    global x_velocity, y_velocity 
 
    #ignore autorepeat events 
    if event.keysym in keys_being_held_down:  
        return 
 
    keys_being_held_down.add(event.keysym) 
    acceleration = key_accelerations[event.keysym] 
    x_velocity += acceleration[0] 
    y_velocity += acceleration[1] 
 
def key_released(event): 
    global x_velocity, y_velocity 
    keys_being_held_down.remove(event.keysym) 
    acceleration = key_accelerations[event.keysym] 
    x_velocity -= acceleration[0] 
    y_velocity -= acceleration[1] 
 
def tick(): 
    canvas.move(rect, x_velocity, y_velocity) 
    print(x_velocity, y_velocity) 
    root.after(100,tick) 
 
for key in key_accelerations: 
    root.bind("<{}>".format(key), key_pressed) 
    root.bind("<KeyRelease-{}>".format(key), key_released) 
 
root.after(100, tick) 
root.mainloop() 

(这不一定是最好的方法,但它演示了基本方法)