Getting a TypeError when trying to increase speed of animation using tkinter Getting a TypeError when trying to increase speed of animation using tkinter tkinter tkinter

Getting a TypeError when trying to increase speed of animation using tkinter


The .bind() method returns an event and passes it to the given function.

Have a look here :

def increaseSpeed(self):    if self.sleepTime>5:self.sleepTime-=20def decreaseSpeed(self):    self.sleepTime+=20

Both these function don't take any arguments and so you see an error

So you need to do something like this :

def increaseSpeed(self,event = None): #or def increaseSpeed(self,*args):    #[...]def decreaseSpeed(self,event = None): #or def decreaseSpeed(self,*args):    #[...]

Here's the final working code -

from tkinter import *class controlAnimation:  def __init__(self):    window = Tk()    window.title("Racing Car")    self.width = 250    self.height = 100    self.canvas = Canvas(window, bg="white", width=self.width, height=self.height)    self.canvas.pack()    frame = Frame(window)    frame.pack()    btStop = Button(frame, text = "Stop", command = self.stop)    btStop.pack(side=LEFT)    btStart = Button(frame, text = "Start", command = self.start)    btStart.pack(side=RIGHT)    self.x=0    self.sleepTime = 100    self.canvas.create_rectangle(self.x,90,self.x+60,80,fill="black", tags = "car")    self.canvas.create_oval(self.x+10, 90, self.x+20, 100, fill = "black",tags = "car")    self.dx=3    self.isStopped = False    self.animate()    window.bind("<Up>", self.increaseSpeed)    window.bind("<Down>", self.decreaseSpeed)    window.mainloop()  def stop(self):    self.isStopped = True  def start(self):    self.isStopped = False    self.animate()  def increaseSpeed(self,event = None): #or def increaseSpeed(self,*args):    if self.sleepTime>5:self.sleepTime-=20  def decreaseSpeed(self,event = None): #or def increaseSpeed(self,*args):    self.sleepTime+=20  def animate(self): # Move the message      while not self.isStopped:      self.canvas.move("car", self.dx,0)       self.canvas.after(self.sleepTime)       self.canvas.update()       if self.x < self.width:          self.x += self.dx       else:        self.x = 0         self.canvas.create_rectangle(self.x-60,90,self.x,80,fill="black", tags = "car")        self.canvas.create_oval(self.x-50, 90, self.x-40, 100, fill = "black",tags = "car")controlAnimation() 


When using widget.bind("<Event>", func) the function passes an extra event to the function and you can use it if you like but apparently you don't need it so you can replace your binds in init with this:

    # You can either get the event using lambda if you don't want anything to do with it like this:    window.bind("<Up>", lambda event: self.increaseSpeed)    window.bind("<Down>", lambda event2: self.decreaseSpeed)

Or in your functions do this:

# Or you can pass it as an argument in your functiondef increaseSpeed(self, event):    if self.sleepTime > 5:        self.sleepTime -= 20def decreaseSpeed(self, event):    self.sleepTime += 20

I believe this is what you are trying to achieve:

from tkinter import *class CarAnimation:    def __init__(self):        self.canvas_width = 550        self.canvas_height = 280        self.car_body_width = 100        self.car_body_height = 50        self.car_wheel_width = 20        self.car_wheel_height = 20        self.car_top_left = 0        self.move_by = 1        self.delay = 20        self.default_delay = 10        self.car_is_moving = False        self.root = Tk()        self.root.resizable(False, False)        self.root.title("Car Animation!")        self.car_canvas = Canvas(self.root, width=self.canvas_width, height=self.canvas_height, background="white",                                 highlightthickness=0)        # If you have more shapes in the canvas that you do not want to get affected by the movement store them as        # below and call the move function for each of them, I just stored them in a variable for demonstration purposes        self.car_body = self.car_canvas.create_rectangle(0, 0, self.car_body_width, self.car_body_height)        self.car_wheel1 = self.car_canvas.create_oval(0, self.car_body_height, self.car_wheel_width,                                                      self.car_body_height+self.car_wheel_height)        self.car_wheel2 = self.car_canvas.create_oval(self.car_body_width-self.car_wheel_width, self.car_body_height,                                                      self.car_body_width, self.car_body_height+self.car_wheel_height)        self.start_btn = Button(self.root, text="Start Car", command=self.start_car)        self.stop_btn = Button(self.root, text="Stop Car", command=self.stop_car)        self.car_canvas.pack(side=TOP)        self.start_btn.pack(side=BOTTOM, pady=5)        self.stop_btn.pack(side=BOTTOM)        self.root.bind("<Up>", self.decrease_delay)        self.root.bind("<Down>", self.increase_delay)        self.root.mainloop()    def start_car(self):        if not self.car_is_moving:            self.car_is_moving = True            self.move_car()    def stop_car(self):        if self.car_is_moving:            self.car_is_moving = False    def move_car(self):        # Instead of storing the car's top left position and appending to it, you can also        # 'self.car_canvas.coords(self.car_body)[0]' so that it would return the shape's coords        if self.car_is_moving and self.car_top_left < self.canvas_width:            self.car_top_left += self.move_by            # You can store their layer numbers and move them one by one but since there were no more shapes            # I decided to move all of them at once using 'ALL'            self.car_canvas.move(ALL, self.move_by, 0)            self.root.after(self.delay, self.move_car)        elif self.car_is_moving and self.car_top_left >= self.canvas_width:            self.car_top_left += -self.canvas_width - self.car_body_width            self.car_canvas.move(ALL, -self.canvas_width - self.car_body_width, 0)            self.root.after(self.delay, self.move_car)    def increase_delay(self, event):        # Added the if statement below so that the user cannot change the delay when the car is not moving        if self.car_is_moving:            self.delay += 10    def decrease_delay(self, event):        if self.delay > self.default_delay and self.car_is_moving:            self.delay -= 10        # You can just delete this elif statement, I just wanted to print out something to the terminal        elif self.delay <= self.default_delay and self.car_is_moving:            print("Delay cannot be lower than default!")if __name__ == '__main__':    CarAnimation()

Note that as mentioned in the code you can use 'self.car_canvas.coords()' instead of storing the top left corner. If you have any questions regarding the code, please ask in the comments