2011-06-08 20 views
1

我是一名高中程序设计专业的学生,​​我有一个小问题。我一直负责在Tkinter编写一个简单的游戏,在那里冰柱从天花板上掉下来,你必须用鼠标避免它。够简单。但是,我遇到了一个问题。每当我在Tkinter应用程序中运行循环时,它都不会打开。我已经尝试过使用time.sleep()每隔0.5秒暂停一次的for循环,只要循环结束,窗口就会打开。我需要做些什么特殊的事情来让循环在Tkinter中工作?沿着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次,然后窗口打开。帮帮我?

+0

可能是回答:http://stackoverflow.com/questions/459083/how-do-you-run-your-own-code-alongside-tkinters-event-loop – schlenk 2011-06-08 20:17:52

回答

5

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

由于已经有一个循环运行,所以不需要创建另一个循环。您只需要逐个添加一些作业到事件队列中。实际上,每个工作都是内部循环的一次迭代。

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

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帧每秒)

这听起来很复杂,但实际上一旦你做了一次或两次真的很容易。