Reputation: 43
I've been trying to do some type checking by in an Entry widget by attaching a handler function that is provided the both the entry and the expected type (a Type class object from the built-in type() function). All works well except it appears the validatecommand changes the type of the Type object from Type to a string, which is not insurmountable but has made me curious what's going on.
See the minimum reproducible example below - note the handler is correctly passed the type object in native python, but with tkinter the type of the type object changes to string.
#NATIVE PYTHON
variable = 'HelloWorld'
vartype = type(variable)
print('VALUE OF VARTYPE: ', vartype, 'TYPE OF VARTYPE: ', type(vartype))
def handler(variable,vartype):
print('VALUE OF VARTYPE: ', vartype, 'TYPE OF VARTYPE: ', type(vartype))
handler(variable,vartype)
#TKINTER VALIDATE HANDLER
import tkinter as tk
top = tk.Tk()
frame = tk.Frame(top)
frame.pack()
vcmd =frame.register(handler)
entry = tk.Entry(frame, validate = 'focusout', validatecommand = (vcmd,"%P",vartype))
entry.pack()
top.mainloop()
The way out of this has been to make a lambda wrapper for the handler which avoids passing the type object to validatecommand:
#NATIVE PYTHON
variable = 'HelloWorld'
vartype = type(variable)
print('VALUE OF VARTYPE: ', vartype, 'TYPE OF VARTYPE: ', type(vartype))
def handler(*variable,vartype=vartype):
print('VALUE OF VARTYPE: ', vartype, 'TYPE OF VARTYPE: ', type(vartype))
handler(*variable,vartype=vartype)
#TKINTER VALIDATE HANDLER
import tkinter as tk
top = tk.Tk()
frame = tk.Frame(top)
frame.pack()
vcmd =frame.register(lambda *args, vartype=vartype : handler(*args,vartype=vartype))
entry = tk.Entry(frame, validate = 'focusout', validatecommand = (vcmd,"%P"))
entry.pack()
top.mainloop()
However, I have still somewhat unsatisfied not knowing what happened with the first iteration - what am I doing wrong there?
Upvotes: 2
Views: 183
Reputation: 385880
All works well except it appears the validatecommand changes the type of the Type object from Type to a string, which is not insurmountable but has made me curious what's going on.... However, I have still somewhat unsatisfied not knowing what happened with the first iteration - what am I doing wrong there?
You are doing nothing wrong, except trying to do something that by design tkinter doesn't support.
Tkinter is an object-oriented wrapper around an embedded Tcl interpreter. This embedded interpreter knows nothing about python objects, so python objects cannot be passed into or retrieved from the Tcl interpreter. When you pass a python function as an argument, tkinter must convert it to a string before it can be handled by the Tcl interpreter.
This is why you must register python functions with the Tcl interpreter. Tkinter will create an internal Tcl function that knows how to call your python function. The name of this function can then be used inside of the Tcl interpreter.
Upvotes: 2