Itemconfigure () and memory leak using tkinter

My code (see below) should display a start / stop button, a zoom button to select a render speed and a canvas with many rectangles that randomly change color over time.

When I run this piece of code, memory usage increases dramatically over time (if you run, you need to increase the speed to 10 to see it easier). At work (on a Windows 7 workstation), where I tested it first, it becomes almost unusable (it becomes very slow) after a few minutes, while on my Mac laptop it survives a little longer, although memory usage is growing steadily.

After searching for the culprit, I came across several threads, including this one from the Tk Toolkit, which dates back to 2010, where they mention that there is a problem with itemconfigure()when it is used to change color, which is exactly what I do.

Commenting out a function "self.update_canvas()"in a function self.run_InfiniteT_MC()solves the problem as far as I can see, and seems to agree with the diagnostics, which itemconfigure()can be problematic for color changes.

Note that I also tried to delete the changing rectangles with the command self.canvas.delete (self.rect [i]) "and then recreate them, but that does not change the memory problem at all.

I also tried to destroy the entire canvas with "self.canvas.destroy()"and recreate everything from scratch every time you need to update the image, but again, that cannot solve the problem with my memory.

Is there anything I can do to solve this memory problem without changing all my code (here is just a small part)?

EDIT: after correct detuning of the command, the self.afterproblem disappeared; therefore, the team is itemconfigure()not to blame at all, at least not for this problem.

from tkinter import *
from numpy import *
from random import randint

class Application(Frame):
    def __init__(self,master):
        Frame.__init__(self,master)
        self.columnconfigure(0, pad = 10)
        self.grid()
        self.count = 0
        self.create_widgets()


def create_widgets(self):
        "create an array of cells all initiated with the same value"
        self.nx = 70
        self.ny = self.nx
        self.ntot = self.nx*self.ny
        self.state = [0 for x in range(self.ntot)]
        for x in range(self.ntot):
            self.state[x] = 0 #0 is down, 1 is right, 2 is up, 3 is left ...modulo 4
        "create a scale button to choose speed of dynamics"
        self.ScaleSpeedVar = IntVar
        self.ScaleSpeed = Scale(self, from_=1, to =20, orient = HORIZONTAL, label = "SimuSpeed", variable = self.ScaleSpeedVar, font =('Helvetica','18'))
        self.ScaleSpeed.grid()
        self.ScaleSpeed.set(1)

"create a button that starts/stops the dynamics"
        self.do_run = False
        self.startclick = True
        self.buttonStartStop = Button(self, text = "Start/Stop", font =('Helvetica','18'))
        self.buttonStartStop["command"] = self.start_stop_simu
        self.buttonStartStop.grid()
"create a big canva to contain the simulation cells"
        self.size = 500
        self.canvas = Canvas(self, width=self.size, height=self.size, bg ="red")
        self.canvas.grid()

        self.width = 1
        self.rect = [0 for x in range(self.ntot)]
        for i in range(self.ntot):
            self.rectsize = self.size/self.nx
            self.rect[i] = self.canvas.create_rectangle((i%(self.nx))*self.rectsize, self.rectsize*(i//self.nx), (i%(self.nx))*self.rectsize+self.rectsize, self.rectsize*(i//self.nx)+self.rectsize, fill="red", tag = i, width = self.width)

def start_stop_simu(self):
    if self.startclick:
        self.start_simu()
        self.startclick = False
    else :
        self.stop_simu()
        self.startclick = True

def start_simu(self):
    self.do_run = True
    self.run_InfiniteT_MC()

def stop_simu(self):
    self.do_run = False

def run_InfiniteT_MC(self):
    if self.do_run:
        self.simuspeed = pow(2,self.ScaleSpeed.get())
        for i in range(self.simuspeed):
            self.cellID = randint(0,self.ntot-1)
            self.angle = 2*randint(0,1)-1
            self.state[self.cellID] = (self.state[self.cellID]+self.angle)%4
        self.update_canvas()
    self.after(1, self.run_InfiniteT_MC)

def update_canvas(self):
    for i in range(self.ntot):
        if self.state[i] == 0:
            self.canvas.itemconfig(self.rect[i], fill = "red")
        if self.state[i] == 2:
            self.canvas.itemconfig(self.rect[i], fill = "blue")
        if self.state[i] == 1:
            self.canvas.itemconfig(self.rect[i], fill = "green")
        if self.state[i] == 3:
            self.canvas.itemconfig(self.rect[i], fill = "yellow")
    self.canvas.update_idletasks()


root = Tk()
root.title("Problematic code")
root.geometry("800x600")
app = Application(root)

root.mainloop()
+4
source share
2 answers

, self.after. , , ( ). self.after, if, , , self.do_run False.

+1

tk , , itemconfigure, . , . , , , .

, , , . .

+1

All Articles