Home > Blockchain >  Tkinter CheckBox command line failing - missing 1 required positional argument: 'self'
Tkinter CheckBox command line failing - missing 1 required positional argument: 'self'

Time:06-14

I have some code which I intend to run calculations every time a user makes a change to a tkinter widget. If you click in an edit box, or alter the dropdown box the functions run fine. The problem I am having is that I can't get the command line of the CheckBox to accept the functions. It throws a "missing 1 required positional argument: 'self'" while the code works on all other widgets. Can anyone let me know what I'm doing wrong please? Code below:

      #Import everything from tkinter, messageboxes, ttk and math
      from tkinter import *
      from tkinter import ttk

      Form1=Tk()

      # Calculate Variables - Main function. Run every time a change is made to the form
      def CalcVariables(Msg):
      Msg = "Run Calculations"    
      print(Msg)

      #Run Multiple Funtions - Tied to command lines of box functionality
      def MultipleFunctions(*funcs):
          def FuncLoop(*args, **kwargs):
              for f in funcs:
                  f(*args, **kwargs)
          return FuncLoop    

      #Check Length Box entry is Valid
      def LthCheck(Msg):

          #Check entry is numeric - give warning if not and exit
          try:
              float(Lth.get())
          except:
              Msg = "Length box only numbers."
              print(Msg)
              Lth.focus()
              return   

      #Check Width Box Entry is Valid
      def WthCheck(Msg):
          #Check entry is numeric - give warning if not and exit
          try:
              int(Wth.get())
          except ValueError:
              Msg = "Width box only accepts numbers."
              print(Msg)
              Wth.focus()
              return

      #Length EditBox
      Lth = Entry(Form1,width=10)
      Lth.grid(row=0, column=1, sticky=W)
      Lth.insert(0,10)
      Lth.bind("<FocusOut>",MultipleFunctions(LthCheck, CalcVariables))
      Label (Form1, text="Length") .grid(row=0, column=0, sticky=W)

      #Width EditBox
      Wth = Entry(Form1,width=10)
      Wth.grid(row=1, column=1, sticky=W)
      Wth.insert(0,1)
      Wth.bind("<FocusOut>",MultipleFunctions(WthCheck, CalcVariables))
      Label (Form1, text="Width") .grid(row=1, column=0, sticky=W)

      #Type DropDownBox
      Type = [
          "Type 1", 
          "Type 2",
          ]
      PartStyle = StringVar()
      PartStyle.set(Type[0])
      PartStyleDrop = OptionMenu(Form1, PartStyle, *Type, command=MultipleFunctions(LthCheck, WthCheck, CalcVariables))
      PartStyleDrop.grid(row=3, column=1,sticky=W)
      Label (Form1, text="Part") .grid(row=3, column=0, sticky=W)

      #Check Button
      MT = IntVar()
      ModType = Checkbutton(Form1, text = "Modify", variable = MT, onvalue = 1, offvalue =0, command= MultipleFunctions(LthCheck, WthCheck))
      ModType.grid(row=4,column=0)

      Lth.focus()

      Form1.mainloop()

CodePudding user response:

The error suggests that you are trying to call a function, but not passing it the required parameter self. You actually do not need self in the parameters of any of these functions. self is only necessary in the method of a class. In fact, these functions require no parameters and the error is solved when leaving the parameter list for the functions blank, e.g.

def LthCheck():
    ...

EDIT: However, as mentioned in the comments, this will lead to errors such as "LthCheck() takes 0 positional arguments but 1 was given". This is due to the difference in using bind for interactivity and command for the CheckButton. Functions used when binding to an event, using the .bind method of a widget, will be given an argument. This typically has info about the event. Functions passed as the command argument of the CheckButton will not be passed any arguments. Therefore you could bind the functions to ModType instead of passing them as the command argument, to avoid these errors. The functions then require a parameter, e.g. event, to work in this case.

Here is how the code looks, which I believe solves all current issues:

#Import everything from tkinter, messageboxes, ttk and math
from tkinter import *
from tkinter import ttk

Form1=Tk()

# Calculate Variables - Main function. Run everytime a change is made to the form
def CalcVariables(event):
    print("Run Calculations")

#Run Multiple Funtions - Tied to command lines of box functionality
def MultipleFunctions(*funcs):
    def FuncLoop(*args, **kwargs):
        for f in funcs:
            f(*args, **kwargs)
    return FuncLoop    

#Check Length Box entry is Valid
def LthCheck(event):
    #Check entry is numeric - give warning if not and exit
    try:
        float(Lth.get())
    except:
        print("Length box only numbers.")
        Lth.focus()
        return   

#Check Width Box Entry is Valid
def WthCheck(event):
    #Check entry is numeric - give warning if not and exit
    try:
        int(Wth.get())
    except ValueError:
        print("Width box only accepts numbers.")
        Wth.focus()
        return

#Length EditBox
Lth = Entry(Form1,width=10)
Lth.grid(row=0, column=1, sticky=W)
Lth.insert(0,10)
Lth.bind("<FocusOut>", MultipleFunctions(LthCheck, CalcVariables))
Label(Form1, text="Length").grid(row=0, column=0, sticky=W)

#Width EditBox
Wth = Entry(Form1,width=10)
Wth.grid(row=1, column=1, sticky=W)
Wth.insert(0,1)
Wth.bind("<FocusOut>",MultipleFunctions(WthCheck, CalcVariables))
Label(Form1, text="Width").grid(row=1, column=0, sticky=W)

#Type DropDownBox
Type = [
    "Type 1", 
    "Type 2",
]
PartStyle = StringVar()
PartStyle.set(Type[0])
PartStyleDrop = OptionMenu(Form1, PartStyle, *Type, command=MultipleFunctions(LthCheck, WthCheck, CalcVariables))
PartStyleDrop.grid(row=3, column=1,sticky=W)
Label (Form1, text="Part") .grid(row=3, column=0, sticky=W)

#Check Button
MT = IntVar()
ModType = Checkbutton(Form1, text = "Modify", variable = MT, onvalue = 1, offvalue =0)
ModType.bind("<ButtonRelease>", MultipleFunctions(LthCheck, WthCheck))
ModType.grid(row=4,column=0)

Lth.focus()

Form1.mainloop()

It is worth noting that while working on this code, it might be helpful to but a print statement in the LthCheck and WthCheck functions to see that they are actually called when the checkbox is checked.

  • Related