How can I update the Tkinter canvas in the middle of a function call?

I am writing a Conway game of life using Tkinter, and I want to have a “Go” button that allows the animation to begin, and continue the automatic transition to completion. I use Canvas to paint the environment, but since the Go button should end the function call before updating the canvas, the window just freezes until I kill the process. I tried using canvas.update_idletasks()and canvas.update()(and then a few seconds of sleeping) at the points where I want to update the canvas, but this does not seem to do the trick. Any ideas? Below is my GameOfLife class, the environment class just manages the board of cells.

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()
+5
source share
1 answer

, . - - .

, , , , ( , ). , 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

+7

All Articles