在Tkinter应用程序旁边运行一个循环

时间:2011-06-08 20:03:08

标签: python loops python-2.7 tkinter

我是一名高中编程学生,我有一个小问题。我的任务是在Tkinter写一个简单的游戏,冰柱从天花板上掉下来,你必须用鼠标来避免它。很简单。但是,我遇到了一个问题。每当我在Tkinter应用程序中运行循环时,它都不会打开。我尝试使用for循环,使用time.sleep()每隔0.5秒暂停一次,循环结束后窗口就会打开。在Tkinter中使循环工作需要做些什么特别的事情吗?

from Tkinter import *
import time
import random

class App:
    def __init__(self, parent):
        self.frame = Frame(root, bg= '#1987DF', width=800, height=800)
        self.frame.bind("<Motion>", self.motionevent)
        self.frame.pack()
        #self.run()
    def randhex(self):
        b = "#"
        for i in range(1, 7):
            a = random.randint(0, 15)
            if a == 10:
                a = "A"
            elif a == 11:
                a = "B"
            elif a == 12:
                a = "C"
            elif a == 13:
                a = "D"
            elif a == 14:
                a = "E"
            elif a == 15:
                a = "F"
            b = b+str(a)
        return b

    def motionevent(self, event):
        xpos, ypos, bg = event.x, event.y, self.randhex()
        str1 = "X : %d  Y : %d BG : %s" % (xpos, ypos, bg)
        root.title(str1)
        x,y, delta = 100, 100, 10
        self.frame.config(bg=bg)

    def run(self):
        for i in range(0, 10):
            time.sleep(.5)
            print 'i'
            self.frame.config(bg=self.randhex())

root = Tk()
app = App(root)
root.mainloop()

目前所做的一切都是在鼠标移动时改变背景。如果 init 中表示self.run()的行未被注释,它将打印“i”10次,然后窗口将打开。帮助

1 个答案:

答案 0 :(得分:6)

编写基于事件的程序与编写传统程序不同。已经存在无限循环运行,并且像任何无限循环一样,如果在内部放置另一个循环,则外循环不能继续直到内循环结束。由于外部循环是导致屏幕刷新和事件处理的原因,因此内部循环有效地冻结了应用程序,直到完成为止。

由于已经有循环运行,因此您无需创建另一个循环。您需要做的就是一次向事件队列中添加一些小作业。实际上,每个作业都是内循环的一次迭代。

例如,如果你想编写一个这样的内部循环:

for i in range(10):
    print "i:", i

...您可以在事件队列中添加一个事件,每次事件循环迭代时(或者更确切地说,每次完成处理任何其他事件时),它将执行一次循环迭代。你这样做:

def do_one_iteration(i):
    print "i:", i
    if i < 9:
        root.after_idle(do_one_iteration, i+1)

然后,在第一次调用do_one_iteration之后,它会将自身的下一次迭代放在事件队列中,并继续执行此操作,直到它确定完成为止。

通常,当用户按下按钮时,您会调用do_one_iteration(例如:“开始”按钮)。称之为一次,然后它做了一点工作(即:将冰柱向下移动几个像素),然后重新安排自己。

在游戏开发中,您可能有一个名为update_display的函数,负责重绘所有内容。例如,它可以从每个冰柱的Y坐标中减去1。您可以为左箭头和右箭头添加绑定以移动播放器(通过递增或递减X坐标),更新功能将使用这些新坐标重绘播放器。

顺便说一下,您可以使用after代替after_idle来减慢程序的速度,以便在稍微延迟后调用该函数。该延迟可用于控制帧速率。例如,假设更新几乎是瞬时的(并且可能在您的情况下),使用参数41(毫秒)调用after会产生大约24 fps的帧速率(24帧乘以41毫秒等于984毫秒) ,或大约每秒24帧)

这可能听起来很复杂,但是一旦你做了一次或两次,它在练习中真的很容易。