如何刷新Canvas以显示Python康威生命游戏中动态变化的矩阵网格
解决Tkinter中康威生命游戏Canvas逐代更新的问题
你的核心问题在于两点:一是当前drawgrid每次都会创建新的Canvas控件,没有复用已有的Canvas进行更新;二是缺少触发逐代演化并刷新界面的循环逻辑。下面是修改后的完整解决方案:
修改后的代码
import numpy as np from tkinter import * def makegrid(rows, cols): grid = np.zeros((rows, cols), int) return grid def insertpattern(x, y, pattern, grid): for i in range(pattern.shape[0]): for j in range(pattern.shape[1]): grid[x + i][y + j] = pattern[i][j] return grid def enviroment(x, y, grid): sum = 0 for i in range(3): for j in range(3): if i == 1 and j == 1: continue elif (x - 1 + i < 0) or (y - 1 + j < 0) or (x - 1 + i == grid.shape[0]) or (y - 1 + j == grid.shape[1]): continue else: sum += grid[x - 1 + i][y - 1 + j] return sum def nextgen(grid): grid2 = makegrid(grid.shape[0], grid.shape[1]) for i in range(grid.shape[0]): for j in range(grid.shape[1]): if grid[i][j] == 1: if enviroment(i, j, grid) == 2 or enviroment(i, j, grid) == 3: grid2[i][j] = 1 elif grid[i][j] == 0: if enviroment(i, j, grid) == 3: grid2[i][j] = 1 else: grid2[i][j] = 0 return grid2 # 修改drawgrid:复用已有Canvas,先清空再重绘 def drawgrid(grid, display, cell_size): # 清空Canvas上所有元素 display.delete("all") for i in range(grid.shape[0]): for j in range(grid.shape[1]): fill = "black" outline = "grey" if grid[i][j] == 1: fill = "green" outline = "grey" xmin = j * cell_size xmax = xmin + cell_size ymin = i * cell_size ymax = ymin + cell_size display.create_rectangle(xmin, ymin, xmax, ymax, fill=fill, outline=outline) # 新增更新函数,用after实现定时循环 def update_game(): global grid # 生成下一代网格 grid = nextgen(grid) # 更新Canvas显示 drawgrid(grid, display, CELL_SIZE) # 每隔300ms调用一次自己,控制演化速度 app.after(300, update_game) ROWS = 20 COLS = 20 CELL_SIZE = 30 grid = makegrid(ROWS, COLS) pattern = np.ones((3, 1), int) grid = insertpattern(1, 1, pattern, grid) app = Tk() app.title("Game of life") # 先创建Canvas并打包 display = Canvas(app, width=CELL_SIZE * COLS, height=CELL_SIZE * ROWS) display.pack() # 首次绘制初始网格 drawgrid(grid, display, CELL_SIZE) # 启动演化更新循环 update_game() app.mainloop()
关键修改说明
- 复用Canvas更新:把原来返回新Canvas的
drawgrid改成接受已创建的display参数,先通过display.delete("all")清空旧内容,再重新绘制新网格。 - 定时循环触发:新增
update_game函数,它会生成下一代网格、调用drawgrid刷新界面,然后用app.after(300, update_game)设定300毫秒后再次调用自己,实现无阻塞的逐代演化(可以调整300这个数值来改变速度)。 - 全局变量传递:用
global grid让update_game能修改全局的网格变量,确保每一代的演化是连续的。
内容的提问来源于stack exchange,提问作者Maher Abdellatif
相关产品推荐
相关产品推荐

