TypeError: Missing one required positional argument 'event'

Viewed 1133

Im making a paint program and I keep running into this error however if I change where event.x /event.y are defined the same error comes up but with a different subroutine

here is the code:

class paint:
    def __init__(self,root,canvas):
        self.root = root
        self.mouse_press = False #mouse isnt being pressed

        self.canvas = canvas

        self.canvas.bind('<ButtonPress-1>',self.MouseDown) # when left click is pressed / down the subroutine MouseDown is opened 
        self.canvas.bind('<ButtonRelease-1>',self.MouseUp)#when left click is relased open the MouseUp subroutine         
     
    def MouseDown(self,event):
        self.x = event.x
        self.y = event.y

        self.mouse_press = True # mouse is pressed 
        self.poll() #calls the coodinates subroutine 

    def MouseUp(self,event):
        
        self.poll()
        self.mouse_press = False
        self.root.after_cancel(self.after_id)

    def poll(self):

        if self.mouse_press:
 
            canvas.create_oval(self.x,self.y, self.x+10, self.y+10 , fill = '#f6f65a',outline = '#f6f65a')
            self.after_id = self.root.after(10,self.MouseDown)


def colour_pick():
    colour_choose = colorchooser.askcolor()[1] #opens a colour picker and picks the colour
    print(colour_choose)
    return(colour_choose)

how I am calling the class

p = paint(root,canvas)
root.mainloop()

the error I keep getting:

Traceback (most recent call last):
  File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
    return self.func(*args)
  File "C:\Users\user\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 839, in callit
    func(*args)
TypeError: paint.MouseDown missing 1 required positional argument: 'event'
3 Answers

Your function MouseDown requires an event parameter since you defined it like this:

def MouseDown(self,event):

However, when you call the function from after, you're not passing this argument:

self.after_id = self.root.after(10,self.MouseDown)

Since MouseDown uses the data in the event object, you will need to synthesize an object with the attributes used by the function (ie: .x and .y) or you need to rewrite MouseDown so that it doesn't require an event parameter.

The cause of the error has been explained by Bryan's answer.

For your case, binding on events <Button-1> and <B1-Motion> is enough and don't need to use .after():

class paint:
    def __init__(self, root, canvas):
        self.root = root
        self.canvas = canvas

        self.canvas.bind('<Button-1>', self.mouse_down)
        self.canvas.bind('<B1-Motion>', self.poll)

    def mouse_down(self, event):
        # save initial drag point
        self.x, self.y = event.x, event.y

    def poll(self, event):
        # draw line from last saved point to current point instead of drawing circle
        self.canvas.create_line(self.x, self.y, event.x, event.y, fill='#f6f65a', width=10, capstyle='round')
        # save current point
        self.x, self.y = event.x, event.y

You are working too hard in trying to fake <Motion>. The below illustrates what I believe you are actually trying to do.

import tkinter as tk


class Canvas(tk.Canvas):
    def __init__(self, master, **kwargs):
        tk.Canvas.__init__(self, master, **{'background':'#000000', 'highlightthickness':0, **kwargs})
        self.bind('<Motion>', self.motion)
    
    #instead of attempting to programmatically toggle up and down states
    def motion(self, e):
        if (e.state & 256) == 256: #if mouse 1 is down
            self.create_oval(e.x, e.y, e.x+10, e.y+10, fill='#f6f65a', outline='#f6f65a') #fill and outline should actually come from your ColorChooser
        

class Root(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.paint = Canvas(self)
        self.paint.pack(expand=True, fill=tk.BOTH)
        

if __name__ == '__main__':
    Root().mainloop()


Related