So I'm trying to use an OptionMenu to switch between a list of items that are drawn on a window. I'm able to do this by tracing the OptionMenu's variable and handling the drawing in the trace callback function. This all works beautifully when the code first executes with a default value for the variable. However, as soon as I make a selection with the OptionMenu, I receive this error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\NotActuallyMyRealName\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
TypeError: 'NoneType' object is not callable
I've narrowed the problem down to the OptionMenu and the trace callback. I actually stripped the script down to the point where it's basically the OptionMenu example in Tkinter's documentation, and I'm still getting the same error.
from tkinter import *
root = Tk()
def callback():
print("var:" + var.get())
var = StringVar()
var.set("A")
var.trace("w", callback())
op = OptionMenu(root, var, "A", "B", "C")
op.pack()
root.mainloop()
Again here, the callback function DOES execute once with the default var set at "A", but changing var with the OptionMenu throws a TypeError, even if I try to change it back to "A". I can't see what could be causing this with the code stripped down to this point. Is the OptionMenu function in Tkinter simply no longer working?
Try this.
When you call a function in trace, you should call the function by just its name. However, in trace, it passes three arguments to the function (you don't need them for your purpose: see What are the arguments to Tkinter variable trace method callbacks? for details). So you can define a lambda function to have 3 dummy arguments and call your callback function.
from tkinter import *
root = Tk()
def callback():
print("var:" + var.get())
var = StringVar()
var.set("A")
var.trace("w", lambda x,y,z: callback())
op = OptionMenu(root, var, "A", "B", "C")
op.pack()
root.mainloop()
Or you can also define your callback function with three dummy arguments:
from tkinter import *
root = Tk()
def callback(a,b,c):
print("var:" + var.get())
var = StringVar()
var.set("A")
var.trace("w", callback)
op = OptionMenu(root, var, "A", "B", "C")
op.pack()
root.mainloop()
Both approaches should work.