Alexander Zagajewski
Alexander Zagajewski

Reputation: 43

Tkinter validatecommand command mangles argument type?

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

Answers (1)

Bryan Oakley
Bryan Oakley

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

Related Questions