Search code examples
pythonmultithreadinganimationtkinterpython-multithreading

Why is my simple tkinter animation lagging?


I was experimenting with tkinter module and wanted to spawn 2 witches going down. So I checked some documentation about threading in python and implemented it. I was surprised by the fact that it was pretty laggy for such a simple program.

Any suggestions why? What I did wrong? Have I missed anything important?

import tkinter
from threading import Thread
from random import randint
canvas = tkinter.Canvas(width=1000,height=500)
canvas.pack()

class Witch:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y
        self.tag = "witch-%d" % id(self)
        self.tags = ("witch", self.tag)
        self.draw_witch(self.x, self.y)

    def draw_witch(self, x, y):
        canvas.create_oval(x,y-20,x+20,y, tags=self.tags)
        canvas.create_rectangle(x,y,x+20,y+40, tags=self.tags)
        canvas.create_line(x+40,y+20,x-20,y+20, tags=self.tags)
        for i in range(-4,4):
            canvas.create_line(x-40,y+20+i*5,x-20,y+20, tags=self.tags)
    
    def move(self, speed):
        canvas.move(self.tag, speed, speed)


def landing(x, y):
    entity = Witch(x, y)
    speed = randint(1,10)
    while canvas.coords(entity.tag)[2]+40 < 1000 and canvas.coords(entity.tag)[3]+40 < 500:
        entity.move(speed)
        canvas.after(10)
        canvas.update()

for _ in range(2):
    t = Thread(target=landing, args=(randint(50, 400), randint(50, 200)))
    t.start()

canvas.mainloop()

Solution

  • Dont use threading if there is no process that would requier it. The after method works just fine.

    import tkinter
    from random import randint
    
    
    canvas = tkinter.Canvas(width=1000,height=500)
    canvas.pack()
    
    class Witch:
        def __init__(self, x=0, y=0):
            self.x = x
            self.y = y
            self.tag = "witch-%d" % id(self)
            self.tags = ("witch", self.tag)
            self.draw_witch(self.x, self.y)
    
        def draw_witch(self, x, y):
            canvas.create_oval(x,y-20,x+20,y, tags=self.tags)
            canvas.create_rectangle(x,y,x+20,y+40, tags=self.tags)
            canvas.create_line(x+40,y+20,x-20,y+20, tags=self.tags)
            for i in range(-4,4):
                canvas.create_line(x-40,y+20+i*5,x-20,y+20, tags=self.tags)
        
        def move(self, speed):
            canvas.move(self.tag, speed, speed)
    
    
    def landing(x, y):
        entity = Witch(x, y)
        speed = randint(1,10)
        animate(entity,speed)
    def animate(entity,speed):
        if canvas.coords(entity.tag)[2]+40 < 1000 and canvas.coords(entity.tag)[3]+40 < 500:
            entity.move(speed)
            canvas.after(10,animate,entity,speed)
    
    landing(randint(50, 400), randint(50, 200))
    landing(randint(50, 400), randint(50, 200))
    
    canvas.mainloop()