2012-06-09 37 views
4

我正在使用Tkinter编写康威的生活游戏,我想要一个允许动画开始的“开始”按钮,并自动继续步进直到终止。我使用Canvas绘制环境,但由于“Go”按钮需要在更新画布之前完成函数调用,因此窗口会挂起,直到我终止进程。我试图用canvas.update_idletasks()canvas.update()(接着睡几秒钟)在我想更新画布的点上,但这似乎并没有成功。有任何想法吗?以下是我的GameOfLife类,Environment类仅管理单元的“板”。如何在函数调用过程中更新Tkinter画布?

from Tkinter import * 
from random import * 
from time import time 
from Environment import * 

class GameOfLife(object): 
    def __init__(self, master, envDim): 
     self.unitSize = 10 
     self.dimension = envDim * self.unitSize 
     self.environment = Environment(envDim) 
     self.environment.seedBoard() 
     self.started = False 

     frame = Frame(master) 
     frame.pack() 
     Button(frame, text = "Go", command = self.go_call).pack(side = LEFT) 
     Button(frame, text = "Clear", command = self.reset_call).pack(side = LEFT) 
     Button(frame, text = "Close", command = frame.quit).pack(side = RIGHT) 
     canvas = self.drawCanvas(master, self.dimension) 

def drawCanvas(self, master, dimension): 
    self.canvas = Canvas(master, width = self.dimension, height = self.dimension) 
    self.canvas.pack() 
    return self.canvas 

def go_call(self): 
    print "<< Go Call >>" 
    if self.environment.started == False: 
     self.environment.seedBoard() 

    self.drawState(self.environment) 
    self.environment.nextBoard() 
    self.started = True 
    while True: 
     self.environment.nextBoard() 
     self.canvas.delete(ALL) 
     self.drawState(self.environment) 
     self.canvas.update_idletasks() 
     sleep(4) 

def reset_call(self): 
    print "<< Reset Call >>" 
    self.canvas.delete(ALL) 
    self.environment = Environment(self.environment.dim) 

def drawState(self, environment): 
    size = self.unitSize 
    for x in range(environment.dim): 
     for y in range(environment.dim): 
      if environment.matrix[x][y].alive == True: 
       xs = x * size 
       ys = y * size 
       self.canvas.create_rectangle(xs, ys, xs+size, ys+size, fill = 'black') 

envDim = 70 
root = Tk() 
gol = GameOfLife(root, envDim) 
root.mainloop() 
+0

小建议。看起来您要删除所有画布对象,并在每次状态更新时创建新对象。将相同的矩形保留在画布上并在每次迭代中更改其填充颜色可能会更有效。 –

+0

为什么“睡觉”4秒钟,是不是很多? – Amr

+1

与问题无关,但在示例代码中执行像您这样的导入确实是一个糟糕的主意 - 除非您确切知道每个模块导出的内容可能很容易产生名称冲突。作为一个经验法则,你不应该'输入*'。 –

回答

7

你不应该把一个无限循环的GUI程序里面,你一定要永远不会调用sleep。您已经有一个无限循环运行 - 事件循环 - 请充分利用它。

这样做动画的方法是编写一个绘制一帧动画(或转动游戏,选择你的隐喻)的函数。然后,通过after调用它自己的功能。

粗略地讲你的代码应该是这样的:

def draw(self): 
    # draw the board according to the current state 
    ... 
    # arrange for the next frame to draw in 4 seconds 
    self.after(4000, self.draw) 

def __init__(self, ...): 
    ... 
    self.go = tk.Button(self, text="Go", command=self.draw) 
    ... 

如果你想添加一个停止按钮,它需要做的所有设置的标志。然后,在draw中,只需在致电之前检查标志self.after