Tkinter Python: How to pass more than one argument through a lambda function in an OptionMenu Tkinter Python: How to pass more than one argument through a lambda function in an OptionMenu tkinter tkinter

Tkinter Python: How to pass more than one argument through a lambda function in an OptionMenu


The command function for an OptionMenu widget takes only one argument: the selected item.

  1. Are you calling the command function? Answer: No.
  2. Who is calling the command function? Answer: python.

Python stores the function you specify somewhere, then at some time in the future after you make a selection in the OptionsMenu, python calls the command function. So python gets to decide how many arguments it will pass to the command function, and it turns out that python calls the command function with one argument:

 command(selection)
  1. How do you know that python calls the command function with one argument? Answer: You check the docs.

  2. What happens if you can't find anything in the docs that describes the type of function you need to assign to command? Answer: You test it out.

First:

......def do_stuff(x):    print(x)tk.OptionMenu(    root,     str_var,     *OPTIONS,    command=do_stuff).pack()......--output:--Storm

Next:

......def do_stuff(x, y):    print(x, y)tk.OptionMenu(    root,     str_var,     *OPTIONS,    command=do_stuff).pack()......--output:--> TypeError: do_stuff() missing 1 required positional argument: 'y'

There are various ways to solve that problem...

Use python's scoping rules:

import tkinter as tkOPTIONS = [        "Fire",        "Ice",        "Storm",        "Life",        "Myth",        "Death",        "Balance"]root = tk.Tk()root.title("Hello")root.geometry("300x200+10+100")frame = [1, 2, 3]def do_stuff(selection):      print(selection, frame)  #frame is visible inside the def.str_var = tk.StringVar(root)str_var.set(OPTIONS[0]) # default valuetk.OptionMenu(    root,     str_var,     *OPTIONS,    command=do_stuff).pack()root.mainloop()

But it's not really a good idea to have functions manipulating global variables, so you can...

Use a wrapper function:

import tkinter as tkOPTIONS = [        "Fire",        "Ice",        "Storm",        "Life",        "Myth",        "Death",        "Balance"]root = tk.Tk()root.title("Hello")root.geometry("300x200+10+100")def wrapper(other):    def do_stuff(selection):        print(selection, other)    return do_stuffstr_var = tk.StringVar(root)str_var.set(OPTIONS[0]) # default valuetk.OptionMenu(    root,     str_var,     *OPTIONS,    command=wrapper('xxxx')  #This actually executes wrapper(), and a                             #function call in your code is replaced                             #by its return value--which happens to                              #be the name of a function that takes one                             #argument.  The one arg function name is                             #then assigned to command.).pack()root.mainloop()

Use a default value for your extra parameter variable:

frame = [1, 2, 3]def do_stuff(selection, other=frame):  #<****HERE****    print(selection, other)str_var = tk.StringVar(root)str_var.set(OPTIONS[0]) # default valuetk.OptionMenu(    root,     str_var,     *OPTIONS,    command=do_stuff).pack()

Warning: Default values for parameter variables have their own issues. The default value is assigned once when the function is defined. Subsequently, no matter how many times you execute the function the same value is used for the default. That means that if the default value is a list, and the first time you call the function you change that list, then the next time you call the function the default value will be the changed list.