Search code examples
pythonvalidationtkintertkinter-entry

Missing positional argument in an validation callback function


Based on a suggestion by stackoverflow I have applied the validation methodology to constrain user input of entries. However, Python returns with an error code while I have inserted the ‘is_okay’ function in the register stateement. This is Python’s type error response:

TypeError: _register() missing 1 required positional argument: 'func
import tkinter as tk
class Window():
    def __init__(self):
        tk.Label(master, text ='Fox number').grid(row=0,column=0)
        tk.Label(master, text ='Hare number').grid(row=1,column=0)
        vcmd = (tk.Entry.register(self.is_okay),'%P')        
        self.fox_entry=tk.Entry(master,width=5, validate="key", validatecommand = vcmd)
        self.fox_entry.grid(row=0, column=1)
        self.hare_entry=tk.Entry(master, width=5, validate="key", validatecommand = vcmd)
        self.hare_entry.grid(row=1, column=1)

    def is_okay(self,value): # entry rule
        return isinstance(value,int) and value >= 0

class Ecosystem():
    def __init__(self):
        self.foxnumber = 10
        self.harenumber = 100

    def initiate(self):        
        def input_user(entry):
            self.inputvalue = None

            def get_value(event):
                self.inputvalue = entry.get()
                print(self.inputvalue)
                return self.inputvalue

            entry.bind('<Return>', get_value)
            return self.inputvalue

        my_win.fox_entry.insert(0,self.foxnumber)
        my_win.hare_entry.insert(0,self.harenumber)
        self.foxnumber = input_user(my_win.fox_entry)  
        self.harenumber = input_user(my_win.hare_entry)       

master = tk.Tk()
my_win = Window()
my_ecosystem = Ecosystem()
my_ecosystem.initiate()
master.mainloop()```



Solution

  • The error you mention happens because you are invoking register on the Entry class and you should invoke it on an Entry instance.

    Give an attentive look into here

    The code below works.

    import tkinter as tk
    
    class Window():
        def __init__(self):
            tk.Label(master, text ='Fox number').grid(row=0,column=0)
            tk.Label(master, text ='Hare number').grid(row=1,column=0)
            self.fox_entry=tk.Entry(master,width=5, validate="key")
            self.fox_entry['validatecommand'] =\
                self.fox_entry.register(self.is_okay),'%P'
            self.hare_entry=tk.Entry(master, width=5, validate="key")
            self.hare_entry['validatecommand'] =\
                self.hare_entry.register(self.is_okay),'%P'
    
            self.fox_entry.grid(row=0, column=1)
            self.hare_entry.grid(row=1, column=1)
    
        def is_okay(self, P):
            try:
                return P == '' or int(P) >= 0
            except:
                return False
            return True
    
    class Ecosystem():
        def __init__(self):
            self.foxnumber = 10
            self.harenumber = 100
    
        def initiate(self):        
            def input_user(entry):
                self.inputvalue = None
    
                def get_value(event):
                    self.inputvalue = entry.get()
                    print(self.inputvalue)
                    return self.inputvalue
    
                entry.bind('<Return>', get_value)
                return self.inputvalue
    
            my_win.fox_entry.insert(0,self.foxnumber)
            my_win.hare_entry.insert(0,self.harenumber)
            self.foxnumber = input_user(my_win.fox_entry)  
            self.harenumber = input_user(my_win.hare_entry)       
    
    master = tk.Tk()
    my_win = Window()
    my_ecosystem = Ecosystem()
    my_ecosystem.initiate()
    master.mainloop()