When using a callback in a trace
call, the callback
should be able to accept 3 arguments that come from the "tkinter" side. You may modify it to accept your own arguments if you wish, but it must accept at least 3 from tkinter.
To see what these arguments are, we can check out the documentation or do a quick inspection on the example below:
import tkinter as tk
def swap_images(*args):
print(f"I was passed {len(args)} arguments")
for n, arg in enumerate(args):
print(f"Arg {n}: {arg}")
root = tk.Tk()
mode = tk.StringVar(master=root, value="Hello", name="I'm the mode var!")
mode_entry = tk.Entry(master=root, textvariable=mode)
mode_entry.pack()
mode.trace("w", lambda *args: swap_images(*args))
root.mainloop()
Output from the swap_images
function (when modifying the entry):
I was passed 3 arguments
Arg 0: I'm the mode var!
Arg 1:
Arg 2: w
We easily see the first argument is the internal name of the variable and the third is the operation being performed (w
riting).
This, along with this blurb from the documentation I linked above, is enough to figure out what the 2nd argument is:
When the trace triggers, three arguments are appended to commandPrefix so that the actual command is as follows:
commandPrefix name1 name2 op
name1
and name2
give the name(s) for the variable being accessed: if the variable is a scalar then name1
gives the variable's name and name2
is an empty string; if the variable is an array element then name1
gives the name of the array and name2
gives the index into the array; if an entire array is being deleted and the trace was registered on the overall array, rather than a single element, then name1
gives the array name and name2
is an empty string. name1
and name2
are not necessarily the same as the name used in the trace variable command: the upvar command allows a procedure to reference a variable under a different name.
op
indicates what operation is being performed on the variable, and is one of read, write, or unset as defined above.
So what does this mean for you?
The fix is easy -- you need to change how you set your trace so that the lambda accepts the additional arguments. You don't have to use them and you don't even need to pass them to the function you call inside the lambda... But the lambda has to be able to accept them.
Change
mode.trace("w", lambda: swapimages(mode.get()))
to
mode.trace("w", lambda *args: swapimages(mode.get()))
Like I said, you can "throw args
away" by not passing it to the function inside your lambda.