while循环不在tkinter动画中工作

时间:2016-07-26 20:48:19

标签: python loops animation tkinter delay

我正在尝试创建一个转轮的动画,并希望在while循环中有一个小延迟,然后每次更新轮。我已经尝试了tkinter中的“after”函数以及python中的“sleep”函数,但它崩溃或完成了conputation并且只显示了最后一个没有实际动画的位置,因为滚轮正在转动。

我为转轮创建的功能:

def turning():
    #initial wheel position
    global position
    pos(position)

    #infinite loop turning the wheel
    while(1):
        root.after(1000, spin)

def spin():
    global position
    global speed
    delspike() #delete current wheel
    position += speed #calculate next position
    if position > 360:
        position -= 360
    pos(position) #draw new wheel

为什么这不起作用?

3 个答案:

答案 0 :(得分:0)

此代码:

while (1):
    root.after(1000, spin)

..将安排spin函数在1秒内运行。它会在眨眼之间成千上万次。即使你要求spin在一秒钟内运行,while循环本身也会尽可能快地运行并且永远不会停止。它将在第一次旋转之前安排数十万个旋转,然后它们将一个接一个地运行,因为它们都将尝试在一秒钟内运行。

执行动画的正确方法是让函数在一秒钟内再次安排自己:

def spin():
    ...
    root.after(1000, spin)

然后,您在程序开始时只调用spin一次,并且无限期地运行。

答案 1 :(得分:0)

after在您尝试放入循环的函数中使用:

def f():
    ...
    root.after(1000, f)

(1000表示1000毫秒,即1秒。这意味着程序将每1秒执行一次操作。您可以将其更改为您希望的任何数字。) 另外,请注意,在Tkinter中使用无限while循环(while Truewhile 1等)会使窗口无响应。我们在这里讨论了很多。如果您对SO进行了研究,可以找到这个。

答案 2 :(得分:0)

我注意到许多初学者'不知道更好'尝试使用while循环动画tkinter。事实证明,这不是一个愚蠢的想法。我最近想出了如何使用asyncio和3.5 async-await语法中的新功能来完成这项工作。我还为一个简单的应用程序制定了通用模板。我碰巧喜欢这种风格,而不是使用后循环。如果您安装了3.5.2或3.6.0a3(或安装了),则可以运行此代码并将您的旋转器替换为您的旋转器。

import asyncio
import tkinter as tk


class App(tk.Tk):

    def __init__(self, loop, interval=1/120):
        super().__init__()
        self.loop = loop
        self.protocol("WM_DELETE_WINDOW", self.close)
        self.tasks = []
        self.tasks.append(loop.create_task(
                self.rotator(1/60, 1)))
        self.updater(interval)

    async def rotator(self, interval, d_per_int):
        canvas = tk.Canvas(self, height=600, width=600)
        canvas.pack()
        deg = 0
        arc = canvas.create_arc(100, 100, 500, 500,
                                start=0, extent=deg, fill='blue')
        while True:
            await asyncio.sleep(interval)
            deg = (deg + d_per_int) % 360
            canvas.itemconfigure(arc, extent=deg)

    def updater(self, interval):
        self.update()
        self.loop.call_later(interval, self.updater, interval)

    def close(self):
        for task in self.tasks:
            task.cancel()
        self.loop.stop()
        self.destroy()


loop = asyncio.get_event_loop()
app = App(loop)
loop.run_forever()
loop.close()