随着时间的推移,Python Tkinter wireworld动画减速

时间:2014-03-30 10:56:10

标签: python performance tkinter

您好我在python中编写了一个wireworld。我目前正致力于动画\ GUI并面临一些问题。几秒钟后动画会变慢。 我对编程很新,对python和OOP也很陌生,所以我可以接受建议和意见,但我的具体问题是我无法弄清楚错误是什么用我的代码,它需要50%的CPU来显示改变颜色的小方块...

如果有人可以帮助我,那就太好了。

这是我的代码:

import Tkinter as tk
import random as rd


class Universe(object):
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.cells = dict()
        for i in range(0, height):
            for j in range(0, width):
                self.cells[(i, j)] = Cell((i, j), 0, width, height)

    def generate_random(self):
        for current_cell in self.cells:
            self.cells[current_cell].state = rd.randint(0, 3)

    def apply_rules(self):
        next_state = dict()
        for current_cell in self.cells:
            if self.cells[current_cell].state == 3:
                if self.cells[current_cell].count_electron_heads(self) == 1:
                    next_state[current_cell] = 1
                elif self.cells[current_cell].count_electron_heads(self) == 2:
                    next_state[current_cell] = 1
                else:
                    next_state[current_cell] = 3
            elif self.cells[current_cell].state == 2:
                next_state[current_cell] = 3
            elif self.cells[current_cell].state == 1:
                next_state[current_cell] = 2
            else:
                next_state[current_cell] = 0

        for current_cell in next_state:
            self.cells[current_cell].state = next_state[current_cell]

    def plain_text_display(self):
        for i in range(0, self.height):
            row = list()
            for j in range(0, self.width):
                row.append(self.cells[(i, j)].state)
            print(row)


class Cell(object):
    def __init__(self, coordinates, state, universe_width, universe_height):
        self.state = state
        self.coordinates = coordinates
        self.neighborhood = [[self.coordinates[0] - 1, self.coordinates[1] - 1],
                             [self.coordinates[0] - 1, self.coordinates[1]],
                             [self.coordinates[0] - 1, self.coordinates[1] + 1],
                             [self.coordinates[0], self.coordinates[1] - 1],
                             [self.coordinates[0], self.coordinates[1] + 1],
                             [self.coordinates[0] + 1, self.coordinates[1] - 1],
                             [self.coordinates[0] + 1, self.coordinates[1]],
                             [self.coordinates[0] + 1, self.coordinates[1] + 1]]

        for i in range(0, len(self.neighborhood)):
            if self.neighborhood[i][0] < 0:
                self.neighborhood[i][0] = universe_height - 1
            elif self.neighborhood[i][0] > universe_height - 1:
                self.neighborhood[i][0] = 0
            if self.neighborhood[i][1] < 0:
                self.neighborhood[i][1] = universe_width - 1
            elif self.neighborhood[i][1] > universe_width - 1:
                self.neighborhood[i][1] = 0

    def count_electron_heads(self, universe):
        electron_heads_count = 0
        for neighbor_cell_coordinates in self.neighborhood:
            if universe.cells[(neighbor_cell_coordinates[0], neighbor_cell_coordinates[1])].state == 1:
                electron_heads_count += 1
        return electron_heads_count


class GUI(tk.Tk):
    def __init__(self, universe):
        tk.Tk.__init__(self)
        self.cell_size = 12
        self.ui_frame = tk.Frame(self, width=self.cell_size*universe.width, height=60, bg="#282729")
        self.ui_frame.pack(fill="x", expand=True)
        self.cell_canvas = tk.Canvas(self, width=self.cell_size*universe.width, height=self.cell_size*universe.height,
                                     borderwidth=0, highlightthickness=0)
        self.cell_canvas.pack(fill="both", expand=True)
        self.cells = dict()
        for i in range(0, universe.height):
            for j in range(0, universe.width):
                if universe.cells[(i, j)].state == 1:
                    color = "#0099FF"
                elif universe.cells[(i, j)].state == 2:
                    color = "#CCFFFF"
                elif universe.cells[(i, j)].state == 3:
                    color = "#EDBE02"
                else:
                    color = "#0C1010"
                self.cells[(i, j)] = self.cell_canvas.create_rectangle(j*self.cell_size, i*self.cell_size,
                                                                       (j+1)*self.cell_size, (i+1)*self.cell_size,
                                                                       fill=color, tag=universe.cells[(i, j)])
        self.draw_button = tk.Button(self.ui_frame, text="Draw", command=lambda: self.draw(universe))
        self.draw_button.pack(side="left")

    def draw(self, universe):
        for i in range(0, universe.height):
            for j in range(0, universe.width):
                if universe.cells[(i, j)].state == 1:
                    color = "#0099FF"
                elif universe.cells[(i, j)].state == 2:
                    color = "#CCFFFF"
                elif universe.cells[(i, j)].state == 3:
                    color = "#EDBE02"
                else:
                    color = "#0C1010"
                self.cells[(i, j)] = self.cell_canvas.create_rectangle(j*self.cell_size, i*self.cell_size,
                                                                       (j+1)*self.cell_size, (i+1)*self.cell_size,
                                                                       fill=color, tag=universe.cells[(i, j)])
        universe.apply_rules()
        self.after(200, lambda: self.draw(universe))




wireworld = Universe(20, 20)
wireworld.generate_random()
g = GUI(wireworld)

g.mainloop()

1 个答案:

答案 0 :(得分:1)

问题是,你每200毫秒在画布上创建新的400个矩形。仅仅10秒钟就有20,000个矩形。一旦你开始进入成千上万的对象,画布将开始减速。一旦你有超过几十万,它将开始变得非常猛烈。你将在不到一分钟的时间内完成100,000件物品。

您需要调整算法以仅创建一次所有矩形。之后,您只需使用itemconfig方法调整颜色。假设您只想用动画的每一帧更改颜色,请在方法draw中替换用于创建矩形的代码:

self.cell_canvas.itemconfig(self.cells[(i,j)], fill=color)