使用tkinter的after方法

时间:2018-02-19 09:41:26

标签: python tkinter tkinter-canvas

正如所建议的那样,我开始使用.after方法来创建弹跳球GUI,并再次成为一个问题。

from tkinter import*
from tkinter import ttk
import random


class Widg:
    def __init__(self, master):
        master.geometry('600x500+200+150')
        canvas = Canvas(master)
        canvas.pack(fill=BOTH, expand=True)
        oval = canvas.create_oval(1, 1, 11, 11, fill='green')

        def call_func(self):
            for i in range(3):
                rand_x = random.randint(1, 50)
                rand_y = random.randint(1, 50)
                canvas.move(oval, rand_x, rand_y)
                canvas.after(500)
                print('x= ', rand_x)
                print('y= ', rand_y)

        canvas.bind('<ButtonPress-1>', call_func)


def main():

    root = Tk()

    a = Widg(root)

    root.mainloop()


if __name__ == '__main__':
    main()

而且,当我启动它时,它会在小部件后面运行,只显示最终结果。 (没有动画)

UPD .: upd2。:@ tobias_k正式注意到!不会再发生了!谢谢你的回答!

1 个答案:

答案 0 :(得分:2)

您必须在after中指定要调用的函数 - 在您的情况下,调用它的函数相同。如上所述in comments,没有回调函数,after行为就像sleep一样(除了参数是以毫秒而不是秒为单位),即它将等待给定的时间,但这样做会阻止UI,这样就不会注册任何输入,特别是球不是重新绘制直到循环之后。通过回调调用after,每次重新定位和重绘球时,无限期地再次调用该函数。

另请注意,call_func的参数不是 self(与原始代码中一样) - 它不是该类的方法,但是嵌套函数 - 但鼠标单击发出event。您应该将此设置为default-parameter,因为使用after时不会发生任何事件(并且您也不需要它)。此外,似乎没有必要循环;如果您希望球移动得更快,请缩短after的时间,并且self变量使用rand_x/y毫无意义。

def call_func(event=None):
    rand_x = random.randint(-50, 50)
    rand_y = random.randint(-50, 50)
    self.canvas.move(self.oval, rand_x, rand_y)
    self.canvas.after(150, call_func)

如果您希望仅在有限次数内回调函数,则可以添加另一个参数,跟踪重复次数:

def call_func(event=None, repeat=10):
    rand_x = random.randint(-50, 50)
    rand_y = random.randint(-50, 50)
    self.canvas.move(self.oval, rand_x, rand_y)
    if repeat:
        self.canvas.after(150, lambda: call_func(repeat=repeat-1))